[ASTERIXDB-2476][COMP] Array slicing parser syntax
- user model changes: yes
- storage format changes: no
- interface changes: no
Details:
- Added slice parser syntax. [list][start:end], the syntax accepts
end expression as an optional argument, the expression can be
written as [list][start:].
- Added slice parser test cases.
Change-Id: Ie83283bfd0a04257b59b573de3dab6b3e47de1bf
Reviewed-on: https://asterix-gerrit.ics.uci.edu/3046
Sonar-Qube: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Tested-by: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Integration-Tests: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Contrib: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Reviewed-by: Dmitry Lychagin <dmitry.lychagin@couchbase.com>
diff --git a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/LangExpressionToPlanTranslator.java b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/LangExpressionToPlanTranslator.java
index c231fdf..c320bd3 100644
--- a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/LangExpressionToPlanTranslator.java
+++ b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/LangExpressionToPlanTranslator.java
@@ -54,6 +54,7 @@
import org.apache.asterix.lang.common.expression.IfExpr;
import org.apache.asterix.lang.common.expression.IndexAccessor;
import org.apache.asterix.lang.common.expression.ListConstructor;
+import org.apache.asterix.lang.common.expression.ListSliceExpression;
import org.apache.asterix.lang.common.expression.LiteralExpr;
import org.apache.asterix.lang.common.expression.OperatorExpr;
import org.apache.asterix.lang.common.expression.QuantifiedExpression;
@@ -120,7 +121,6 @@
import org.apache.hyracks.algebricks.core.algebra.expressions.ConstantExpression;
import org.apache.hyracks.algebricks.core.algebra.expressions.IExpressionAnnotation;
import org.apache.hyracks.algebricks.core.algebra.expressions.ScalarFunctionCallExpression;
-import org.apache.hyracks.algebricks.core.algebra.expressions.StatefulFunctionCallExpression;
import org.apache.hyracks.algebricks.core.algebra.expressions.UnnestingFunctionCallExpression;
import org.apache.hyracks.algebricks.core.algebra.expressions.VariableReferenceExpression;
import org.apache.hyracks.algebricks.core.algebra.functions.AlgebricksBuiltinFunctions;
@@ -152,7 +152,6 @@
import org.apache.hyracks.algebricks.core.algebra.properties.INodeDomain;
import org.apache.hyracks.algebricks.core.algebra.properties.LocalOrderProperty;
import org.apache.hyracks.algebricks.core.algebra.properties.OrderColumn;
-import org.apache.hyracks.algebricks.core.algebra.properties.UnpartitionedPropertyComputer;
import org.apache.hyracks.algebricks.core.algebra.util.OperatorPropertiesUtil;
import org.apache.hyracks.api.exceptions.SourceLocation;
import org.apache.hyracks.api.io.FileSplit;
@@ -761,6 +760,52 @@
}
@Override
+ public Pair<ILogicalOperator, LogicalVariable> visit(ListSliceExpression expression,
+ Mutable<ILogicalOperator> tupSource) throws CompilationException {
+ SourceLocation sourceLoc = expression.getSourceLocation();
+
+ // Expression pair
+ Pair<ILogicalExpression, Mutable<ILogicalOperator>> expressionPair =
+ langExprToAlgExpression(expression.getExpr(), tupSource);
+ LogicalVariable variable = context.newVar();
+ AbstractFunctionCallExpression functionCallExpression;
+
+ // Start index expression pair
+ Pair<ILogicalExpression, Mutable<ILogicalOperator>> startIndexPair =
+ langExprToAlgExpression(expression.getStartIndexExpression(), expressionPair.second);
+
+ // End index expression can be null (optional)
+ // End index expression pair
+ Pair<ILogicalExpression, Mutable<ILogicalOperator>> endIndexPair = null;
+ if (expression.hasEndExpression()) {
+ endIndexPair = langExprToAlgExpression(expression.getEndIndexExpression(), startIndexPair.second);
+ functionCallExpression = new ScalarFunctionCallExpression(
+ FunctionUtil.getFunctionInfo(BuiltinFunctions.ARRAY_SLICE_WITH_END_POSITION));
+ functionCallExpression.getArguments().add(new MutableObject<>(expressionPair.first));
+ functionCallExpression.getArguments().add(new MutableObject<>(startIndexPair.first));
+ functionCallExpression.getArguments().add(new MutableObject<>(endIndexPair.first));
+ functionCallExpression.setSourceLocation(sourceLoc);
+ } else {
+ functionCallExpression = new ScalarFunctionCallExpression(
+ FunctionUtil.getFunctionInfo(BuiltinFunctions.ARRAY_SLICE_WITHOUT_END_POSITION));
+ functionCallExpression.getArguments().add(new MutableObject<>(expressionPair.first));
+ functionCallExpression.getArguments().add(new MutableObject<>(startIndexPair.first));
+ functionCallExpression.setSourceLocation(sourceLoc);
+ }
+
+ AssignOperator assignOperator = new AssignOperator(variable, new MutableObject<>(functionCallExpression));
+
+ if (expression.hasEndExpression()) {
+ assignOperator.getInputs().add(endIndexPair.second); // NOSONAR: Called only if value exists
+ } else {
+ assignOperator.getInputs().add(startIndexPair.second);
+ }
+
+ assignOperator.setSourceLocation(sourceLoc);
+ return new Pair<>(assignOperator, variable);
+ }
+
+ @Override
public Pair<ILogicalOperator, LogicalVariable> visit(CallExpr fcall, Mutable<ILogicalOperator> tupSource)
throws CompilationException {
LogicalVariable v = context.newVar();
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_slice/array_slice_null_result/array_slice_null_result.3.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_slice/array_slice_null_result/array_slice_null_result.3.query.sqlpp
index 4a20935..65d7975 100755
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_slice/array_slice_null_result/array_slice_null_result.3.query.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/array_fun/array_slice/array_slice_null_result/array_slice_null_result.3.query.sqlpp
@@ -35,7 +35,11 @@
"t13": (array_slice([0, 1, 2, 3], "0", 3) IS NULL), // Invalid start
"t14": (array_slice([0, 1, 2, 3], 0, "3") IS NULL), // Invalid end
"t15": (SELECT value array_slice(d1.followers, null) IS NULL FROM d1), // start is null
- "t16": (SELECT value array_slice(d1.followers, null, 2) IS NULL FROM d1) // start is null
+ "t16": (SELECT value array_slice(d1.followers, null, 2) IS NULL FROM d1), // start is null
+ "t17": (array_slice([0, 1, 2, 3], float("INF")) IS NULL), // INF
+ "t18": (array_slice([0, 1, 2, 3], float("NaN")) IS NULL), // NaN
+ "t19": (array_slice([0, 1, 2, 3], 1, float("INF")) IS NULL), // INF
+ "t20": (array_slice([0, 1, 2, 3], 2, float("NaN")) IS NULL) // NaN
};
// t15 has MISSING value in first record, so result will actually be [ null, true ]
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/list/list-slice_01/list-slice_01.1.ddl.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/list/list-slice_01/list-slice_01.1.ddl.sqlpp
new file mode 100644
index 0000000..f5237ec
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/list/list-slice_01/list-slice_01.1.ddl.sqlpp
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+drop dataverse test if exists;
+create dataverse test;
+use test;
+
+drop type testType if exists;
+create type testType as open {
+id: int64,
+groupId: int64,
+name: string,
+arrayItems: [int64],
+multisetItems: {{ int64 }}
+};
+
+drop dataset test if exists;
+create dataset test(testType) primary key id;
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/list/list-slice_01/list-slice_01.2.update.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/list/list-slice_01/list-slice_01.2.update.sqlpp
new file mode 100644
index 0000000..682b9e5
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/list/list-slice_01/list-slice_01.2.update.sqlpp
@@ -0,0 +1,26 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+use test;
+
+insert into test.test([
+{"id": 1, "groupId": 1, "name": "Name value", "arrayItems": [1, 2, 3], "multisetItems": {{1, 2, 3}}},
+{"id": 2, "groupId": 1, "name": "Name value", "arrayItems": [1, 2, 3, 4], "multisetItems": {{1, 2, 3, 4}}, "openArrayItems": null},
+{"id": 3, "groupId": 2, "name": "Name value", "arrayItems": [1, 2, 3, 4, 5], "multisetItems": {{1, 2, 3, 4, 5}}, "openArrayItems": [1, 2, 3]}
+]);
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/list/list-slice_01/list-slice_01.3.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/list/list-slice_01/list-slice_01.3.query.sqlpp
new file mode 100644
index 0000000..363235b
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/list/list-slice_01/list-slice_01.3.query.sqlpp
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+use test;
+
+{
+"t1": [1, 2, 3][0:], // ok
+"t2": [1, 2, 3][0:2], // ok
+"t3": [1, 2, 3][-3:3], // ok
+"t4": [1, 2, 3][0:-1], // ok
+"t5": [1, 2, 3][-2:-1], // ok
+"t6": [1, 2, 3][(0+1):], // ok
+"t7": [1, 2, 3][(0+1):(0+2)], // ok
+"t8": (select value openArrayItems[0:2] from test order by id asc), // ok
+"t9": (select value openArrayItems[0:(1+1)] from test order by id asc), // ok
+"t10": ((select value arrayItems from test where id = 1)[0][0:]), // ok
+"t11": ((select value arrayItems from test where id = 1)[0][0:(1+2)]) // ok
+};
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/list/list-slice_02/list-slice_02.1.ddl.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/list/list-slice_02/list-slice_02.1.ddl.sqlpp
new file mode 100644
index 0000000..f5237ec
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/list/list-slice_02/list-slice_02.1.ddl.sqlpp
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+drop dataverse test if exists;
+create dataverse test;
+use test;
+
+drop type testType if exists;
+create type testType as open {
+id: int64,
+groupId: int64,
+name: string,
+arrayItems: [int64],
+multisetItems: {{ int64 }}
+};
+
+drop dataset test if exists;
+create dataset test(testType) primary key id;
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/list/list-slice_02/list-slice_02.2.update.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/list/list-slice_02/list-slice_02.2.update.sqlpp
new file mode 100644
index 0000000..682b9e5
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/list/list-slice_02/list-slice_02.2.update.sqlpp
@@ -0,0 +1,26 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+use test;
+
+insert into test.test([
+{"id": 1, "groupId": 1, "name": "Name value", "arrayItems": [1, 2, 3], "multisetItems": {{1, 2, 3}}},
+{"id": 2, "groupId": 1, "name": "Name value", "arrayItems": [1, 2, 3, 4], "multisetItems": {{1, 2, 3, 4}}, "openArrayItems": null},
+{"id": 3, "groupId": 2, "name": "Name value", "arrayItems": [1, 2, 3, 4, 5], "multisetItems": {{1, 2, 3, 4, 5}}, "openArrayItems": [1, 2, 3]}
+]);
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/list/list-slice_02/list-slice_02.3.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/list/list-slice_02/list-slice_02.3.query.sqlpp
new file mode 100644
index 0000000..ffa35d3
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/list/list-slice_02/list-slice_02.3.query.sqlpp
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+use test;
+
+{
+"t1": (select value openArrayItems[0:] is missing from test order by id asc), // ok [ true, false, false ]
+"t2": (select value openArrayItems[0:] is null from test order by id asc), // ok [ null, true, false ] (first item is missing)
+"t3": (select value openArrayItems[string("Hello"):2] is null from test order by id asc),
+"t4": (select value openArrayItems[float("INF"):2] is null from test order by id asc),
+"t5": (select value openArrayItems[float("-INF"):] is null from test order by id asc),
+"t6": (select value openArrayItems[float("NaN"):] is null from test order by id asc)
+};
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/list/list-slice_03/list-slice_03.1.ddl.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/list/list-slice_03/list-slice_03.1.ddl.sqlpp
new file mode 100644
index 0000000..f5237ec
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/list/list-slice_03/list-slice_03.1.ddl.sqlpp
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+drop dataverse test if exists;
+create dataverse test;
+use test;
+
+drop type testType if exists;
+create type testType as open {
+id: int64,
+groupId: int64,
+name: string,
+arrayItems: [int64],
+multisetItems: {{ int64 }}
+};
+
+drop dataset test if exists;
+create dataset test(testType) primary key id;
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/list/list-slice_03/list-slice_03.2.update.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/list/list-slice_03/list-slice_03.2.update.sqlpp
new file mode 100644
index 0000000..682b9e5
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/list/list-slice_03/list-slice_03.2.update.sqlpp
@@ -0,0 +1,26 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+use test;
+
+insert into test.test([
+{"id": 1, "groupId": 1, "name": "Name value", "arrayItems": [1, 2, 3], "multisetItems": {{1, 2, 3}}},
+{"id": 2, "groupId": 1, "name": "Name value", "arrayItems": [1, 2, 3, 4], "multisetItems": {{1, 2, 3, 4}}, "openArrayItems": null},
+{"id": 3, "groupId": 2, "name": "Name value", "arrayItems": [1, 2, 3, 4, 5], "multisetItems": {{1, 2, 3, 4, 5}}, "openArrayItems": [1, 2, 3]}
+]);
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/list/list-slice_03/list-slice_03.3.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/list/list-slice_03/list-slice_03.3.query.sqlpp
new file mode 100644
index 0000000..3c6bf72
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/list/list-slice_03/list-slice_03.3.query.sqlpp
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+use test;
+
+use test;
+{
+"t1": [1, 2, 3][int32("0"):1],
+"t2": [1, 2, 3][double("0"):1],
+"t3": [1, 2, 3][[0, 1][0]:1],
+"t4": [1, 2, 3][array_slice([0, 1], 0, 1)[0]:1],
+"t5": [1, 2, 3][(select value 0)[0]:],
+"t6": [1, 2, 3][(select value 0)[0]:1],
+"t7": [1, 2, 3][(select value 0)[0]:(select value 3)[0]]
+};
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/array_fun/array_slice/array_slice_null_result/array_slice_null_result.3.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/array_fun/array_slice/array_slice_null_result/array_slice_null_result.3.adm
index 1186784..f70f68c 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/results/array_fun/array_slice/array_slice_null_result/array_slice_null_result.3.adm
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/array_fun/array_slice/array_slice_null_result/array_slice_null_result.3.adm
@@ -1 +1 @@
-{ "t1": true, "t2": true, "t3": true, "t4": true, "t5": true, "t6": true, "t7": true, "t8": true, "t9": true, "t10": true, "t11": true, "t12": true, "t13": true, "t14": true, "t15": [ null, true ], "t16": [ null, true ] }
\ No newline at end of file
+{ "t1": true, "t2": true, "t3": true, "t4": true, "t5": true, "t6": true, "t7": true, "t8": true, "t9": true, "t10": true, "t11": true, "t12": true, "t13": true, "t14": true, "t15": [ null, true ], "t16": [ null, true ], "t17": true, "t18": true, "t19": true, "t20": true }
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/list/list-slice_01/list-slice_01.1.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/list/list-slice_01/list-slice_01.1.adm
new file mode 100644
index 0000000..d44662f
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/list/list-slice_01/list-slice_01.1.adm
@@ -0,0 +1 @@
+{ "t1": [ 1, 2, 3 ], "t2": [ 1, 2 ], "t3": [ 1, 2, 3 ], "t4": [ 1, 2 ], "t5": [ 2 ], "t6": [ 2, 3 ], "t7": [ 2 ], "t8": [ null, null, [ 1, 2 ] ], "t9": [ null, null, [ 1, 2 ] ], "t10": [ 1, 2, 3 ], "t11": [ 1, 2, 3 ] }
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/list/list-slice_02/list-slice_02.1.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/list/list-slice_02/list-slice_02.1.adm
new file mode 100644
index 0000000..e5e25ae
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/list/list-slice_02/list-slice_02.1.adm
@@ -0,0 +1 @@
+{ "t1": [ true, false, false ], "t2": [ null, true, false ], "t3": [ null, true, true ], "t4": [ null, true, true ], "t5": [ null, true, true ], "t6": [ null, true, true ] }
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/list/list-slice_03/list-slice_03.1.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/list/list-slice_03/list-slice_03.1.adm
new file mode 100644
index 0000000..4cedf7d
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/list/list-slice_03/list-slice_03.1.adm
@@ -0,0 +1 @@
+{ "t1": [ 1 ], "t2": [ 1 ], "t3": [ 1 ], "t4": [ 1 ], "t5": [ 1, 2, 3 ], "t6": [ 1 ], "t7": [ 1, 2, 3 ] }
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml b/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml
index 9efdcbb..39a3c76 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml
@@ -4641,6 +4641,21 @@
</compilation-unit>
</test-case>
<test-case FilePath="list">
+ <compilation-unit name="list-slice_01">
+ <output-dir compare="Text">list-slice_01</output-dir>
+ </compilation-unit>
+ </test-case>
+ <test-case FilePath="list">
+ <compilation-unit name="list-slice_02">
+ <output-dir compare="Text">list-slice_02</output-dir>
+ </compilation-unit>
+ </test-case>
+ <test-case FilePath="list">
+ <compilation-unit name="list-slice_03">
+ <output-dir compare="Text">list-slice_03</output-dir>
+ </compilation-unit>
+ </test-case>
+ <test-case FilePath="list">
<compilation-unit name="listify_01">
<output-dir compare="Text">listify_01</output-dir>
</compilation-unit>
diff --git a/asterixdb/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/visitor/AQLAstPrintVisitor.java b/asterixdb/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/visitor/AQLAstPrintVisitor.java
index 0c34b83..d8614ac 100644
--- a/asterixdb/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/visitor/AQLAstPrintVisitor.java
+++ b/asterixdb/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/visitor/AQLAstPrintVisitor.java
@@ -28,6 +28,7 @@
import org.apache.asterix.lang.aql.visitor.base.IAQLVisitor;
import org.apache.asterix.lang.common.base.Clause;
import org.apache.asterix.lang.common.base.Expression;
+import org.apache.asterix.lang.common.expression.ListSliceExpression;
import org.apache.asterix.lang.common.visitor.QueryPrintVisitor;
class AQLAstPrintVisitor extends QueryPrintVisitor implements IAQLVisitor<Void, Integer> {
@@ -76,4 +77,10 @@
return null;
}
+ @Override
+ public Void visit(ListSliceExpression expression, Integer step) throws CompilationException {
+ // This functionality is not supported for AQL
+ return null;
+ }
+
}
diff --git a/asterixdb/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/visitor/AQLInlineUdfsVisitor.java b/asterixdb/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/visitor/AQLInlineUdfsVisitor.java
index fb452d2..92ac21f 100644
--- a/asterixdb/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/visitor/AQLInlineUdfsVisitor.java
+++ b/asterixdb/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/visitor/AQLInlineUdfsVisitor.java
@@ -31,6 +31,7 @@
import org.apache.asterix.lang.common.base.Expression;
import org.apache.asterix.lang.common.base.IRewriterFactory;
import org.apache.asterix.lang.common.clause.LetClause;
+import org.apache.asterix.lang.common.expression.ListSliceExpression;
import org.apache.asterix.lang.common.rewrites.LangRewritingContext;
import org.apache.asterix.lang.common.statement.FunctionDecl;
import org.apache.asterix.lang.common.visitor.AbstractInlineUdfsVisitor;
@@ -81,6 +82,12 @@
}
@Override
+ public Boolean visit(ListSliceExpression expression, List<FunctionDecl> arg) throws CompilationException {
+ // This functionality is not supported for AQL
+ return false;
+ }
+
+ @Override
protected Expression generateQueryExpression(List<LetClause> letClauses, Expression returnExpr) {
List<Clause> letList = new ArrayList<Clause>();
letList.addAll(letClauses);
diff --git a/asterixdb/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/visitor/base/AbstractAqlAstVisitor.java b/asterixdb/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/visitor/base/AbstractAqlAstVisitor.java
index a2b9ac6..3b9ed7f 100644
--- a/asterixdb/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/visitor/base/AbstractAqlAstVisitor.java
+++ b/asterixdb/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/visitor/base/AbstractAqlAstVisitor.java
@@ -23,6 +23,7 @@
import org.apache.asterix.lang.aql.clause.ForClause;
import org.apache.asterix.lang.aql.expression.FLWOGRExpression;
import org.apache.asterix.lang.aql.expression.UnionExpr;
+import org.apache.asterix.lang.common.expression.ListSliceExpression;
import org.apache.asterix.lang.common.visitor.base.AbstractAstVisitor;
public abstract class AbstractAqlAstVisitor<R, T> extends AbstractAstVisitor<R, T> implements IAQLVisitor<R, T> {
@@ -47,4 +48,8 @@
return null;
}
+ @Override
+ public R visit(ListSliceExpression expression, T arg) throws CompilationException {
+ return null;
+ }
}
diff --git a/asterixdb/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/visitor/base/AbstractAqlSimpleExpressionVisitor.java b/asterixdb/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/visitor/base/AbstractAqlSimpleExpressionVisitor.java
index 4f52c37..9fb0840 100644
--- a/asterixdb/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/visitor/base/AbstractAqlSimpleExpressionVisitor.java
+++ b/asterixdb/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/visitor/base/AbstractAqlSimpleExpressionVisitor.java
@@ -42,6 +42,7 @@
import org.apache.asterix.lang.common.expression.IfExpr;
import org.apache.asterix.lang.common.expression.IndexAccessor;
import org.apache.asterix.lang.common.expression.ListConstructor;
+import org.apache.asterix.lang.common.expression.ListSliceExpression;
import org.apache.asterix.lang.common.expression.LiteralExpr;
import org.apache.asterix.lang.common.expression.OperatorExpr;
import org.apache.asterix.lang.common.expression.QuantifiedExpression;
@@ -203,6 +204,12 @@
return ia;
}
+ @Override
+ public Expression visit(ListSliceExpression expression, ILangExpression arg) throws CompilationException {
+ // This functionality is not supported for AQL
+ return null;
+ }
+
protected Expression visit(Expression expr, ILangExpression arg) throws CompilationException {
return postVisit(preVisit(expr).accept(this, arg));
}
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/Expression.java b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/Expression.java
index 1066408..bf1b40c 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/Expression.java
+++ b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/Expression.java
@@ -34,6 +34,7 @@
OP_EXPRESSION,
FIELD_ACCESSOR_EXPRESSION,
INDEX_ACCESSOR_EXPRESSION,
+ LIST_SLICE_EXPRESSION,
UNARY_EXPRESSION,
UNION_EXPRESSION,
SELECT_EXPRESSION,
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/expression/ListSliceExpression.java b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/expression/ListSliceExpression.java
new file mode 100644
index 0000000..5749c74
--- /dev/null
+++ b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/expression/ListSliceExpression.java
@@ -0,0 +1,90 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.asterix.lang.common.expression;
+
+import org.apache.asterix.common.exceptions.CompilationException;
+import org.apache.asterix.lang.common.base.Expression;
+import org.apache.asterix.lang.common.visitor.base.ILangVisitor;
+
+import java.util.Objects;
+
+public class ListSliceExpression extends AbstractAccessor {
+ private Expression startIndexExpression;
+ private Expression endIndexExpression;
+
+ public ListSliceExpression(Expression expr, Expression startIndexExpression, Expression endIndexExpression) {
+ super(expr);
+ this.startIndexExpression = startIndexExpression;
+ this.endIndexExpression = endIndexExpression;
+ }
+
+ public Expression getStartIndexExpression() {
+ return startIndexExpression;
+ }
+
+ public Expression getEndIndexExpression() {
+ return endIndexExpression;
+ }
+
+ // Only end expression can be null (Value not provided)
+ public boolean hasEndExpression() {
+ return endIndexExpression != null;
+ }
+
+ public void setStartIndexExpression(Expression startIndexExpression) {
+ this.startIndexExpression = startIndexExpression;
+ }
+
+ public void setEndIndexExpression(Expression endIndexExpression) {
+ this.endIndexExpression = endIndexExpression;
+ }
+
+ @Override
+ public Kind getKind() {
+ return Kind.LIST_SLICE_EXPRESSION;
+ }
+
+ @Override
+ public <R, T> R accept(ILangVisitor<R, T> visitor, T arg) throws CompilationException {
+ return visitor.visit(this, arg);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(expr, startIndexExpression, endIndexExpression);
+ }
+
+ @Override
+ public boolean equals(Object object) {
+ if (this == object) {
+ return true;
+ }
+ if (!(object instanceof ListSliceExpression)) {
+ return false;
+ }
+ ListSliceExpression target = (ListSliceExpression) object;
+ return super.equals(target) && Objects.equals(startIndexExpression, target.startIndexExpression)
+ && Objects.equals(endIndexExpression, target.endIndexExpression);
+ }
+
+ @Override
+ public String toString() {
+ return expr + "[" + (startIndexExpression + ":" + (hasEndExpression() ? endIndexExpression : "")) + "]";
+ }
+}
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/visitor/CloneAndSubstituteVariablesVisitor.java b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/visitor/CloneAndSubstituteVariablesVisitor.java
index 0b907bc..c387a9a 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/visitor/CloneAndSubstituteVariablesVisitor.java
+++ b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/visitor/CloneAndSubstituteVariablesVisitor.java
@@ -41,6 +41,7 @@
import org.apache.asterix.lang.common.expression.IfExpr;
import org.apache.asterix.lang.common.expression.IndexAccessor;
import org.apache.asterix.lang.common.expression.ListConstructor;
+import org.apache.asterix.lang.common.expression.ListSliceExpression;
import org.apache.asterix.lang.common.expression.LiteralExpr;
import org.apache.asterix.lang.common.expression.OperatorExpr;
import org.apache.asterix.lang.common.expression.QuantifiedExpression;
@@ -304,6 +305,33 @@
}
@Override
+ public Pair<ILangExpression, VariableSubstitutionEnvironment> visit(ListSliceExpression expression,
+ VariableSubstitutionEnvironment env) throws CompilationException {
+ Pair<ILangExpression, VariableSubstitutionEnvironment> expressionPair = expression.getExpr().accept(this, env);
+ Expression startIndexExpression;
+ Expression endIndexExpression = null;
+
+ // Start index expression
+ Pair<ILangExpression, VariableSubstitutionEnvironment> startExpressionPair =
+ expression.getStartIndexExpression().accept(this, env);
+ startIndexExpression = (Expression) startExpressionPair.first;
+
+ // End index expression (optional)
+ if (expression.hasEndExpression()) {
+ Pair<ILangExpression, VariableSubstitutionEnvironment> endExpressionPair =
+ expression.getEndIndexExpression().accept(this, env);
+ endIndexExpression = (Expression) endExpressionPair.first;
+ }
+
+ // Resulted expression
+ ListSliceExpression resultExpression =
+ new ListSliceExpression((Expression) expressionPair.first, startIndexExpression, endIndexExpression);
+ resultExpression.setSourceLocation(expression.getSourceLocation());
+ resultExpression.addHints(expression.getHints());
+ return new Pair<>(resultExpression, env);
+ }
+
+ @Override
public Pair<ILangExpression, VariableSubstitutionEnvironment> visit(FieldAccessor fa,
VariableSubstitutionEnvironment env) throws CompilationException {
Pair<ILangExpression, VariableSubstitutionEnvironment> p = fa.getExpr().accept(this, env);
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/visitor/FormatPrintVisitor.java b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/visitor/FormatPrintVisitor.java
index c7f2a5d..6b734dd 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/visitor/FormatPrintVisitor.java
+++ b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/visitor/FormatPrintVisitor.java
@@ -49,6 +49,7 @@
import org.apache.asterix.lang.common.expression.IndexAccessor;
import org.apache.asterix.lang.common.expression.IndexedTypeExpression;
import org.apache.asterix.lang.common.expression.ListConstructor;
+import org.apache.asterix.lang.common.expression.ListSliceExpression;
import org.apache.asterix.lang.common.expression.LiteralExpr;
import org.apache.asterix.lang.common.expression.OperatorExpr;
import org.apache.asterix.lang.common.expression.OrderedListTypeDefinition;
@@ -833,6 +834,22 @@
return null;
}
+ @Override
+ public Void visit(ListSliceExpression expression, Integer step) throws CompilationException {
+ out.println(skip(step) + "ListSliceExpression [");
+ expression.getExpr().accept(this, step + 1);
+ out.print(skip(step + 1) + "Index: ");
+ expression.getStartIndexExpression().accept(this, step + 1);
+ out.println(skip(step) + ":");
+
+ // End index expression can be null (optional)
+ if (expression.hasEndExpression()) {
+ expression.getEndIndexExpression().accept(this, step + 1);
+ }
+ out.println(skip(step) + "]");
+ return null;
+ }
+
protected void printConfiguration(Map<String, String> properties) {
if (properties.size() > 0) {
out.print("(");
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/visitor/GatherFunctionCallsVisitor.java b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/visitor/GatherFunctionCallsVisitor.java
index 625d3e0c..a239df1 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/visitor/GatherFunctionCallsVisitor.java
+++ b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/visitor/GatherFunctionCallsVisitor.java
@@ -36,6 +36,7 @@
import org.apache.asterix.lang.common.expression.IfExpr;
import org.apache.asterix.lang.common.expression.IndexAccessor;
import org.apache.asterix.lang.common.expression.ListConstructor;
+import org.apache.asterix.lang.common.expression.ListSliceExpression;
import org.apache.asterix.lang.common.expression.LiteralExpr;
import org.apache.asterix.lang.common.expression.OperatorExpr;
import org.apache.asterix.lang.common.expression.OrderedListTypeDefinition;
@@ -100,6 +101,17 @@
}
@Override
+ public Void visit(ListSliceExpression expression, Void arg) throws CompilationException {
+ expression.getExpr().accept(this, arg);
+ expression.getStartIndexExpression().accept(this, arg);
+
+ if (expression.hasEndExpression()) {
+ expression.getEndIndexExpression().accept(this, arg);
+ }
+ return null;
+ }
+
+ @Override
public Void visit(LetClause lc, Void arg) throws CompilationException {
lc.getBindingExpr().accept(this, arg);
return null;
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/visitor/base/ILangVisitor.java b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/visitor/base/ILangVisitor.java
index cace925..ce6ae6b 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/visitor/base/ILangVisitor.java
+++ b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/visitor/base/ILangVisitor.java
@@ -30,6 +30,7 @@
import org.apache.asterix.lang.common.expression.IfExpr;
import org.apache.asterix.lang.common.expression.IndexAccessor;
import org.apache.asterix.lang.common.expression.ListConstructor;
+import org.apache.asterix.lang.common.expression.ListSliceExpression;
import org.apache.asterix.lang.common.expression.LiteralExpr;
import org.apache.asterix.lang.common.expression.OperatorExpr;
import org.apache.asterix.lang.common.expression.OrderedListTypeDefinition;
@@ -175,4 +176,5 @@
R visit(CompactStatement del, T arg) throws CompilationException;
+ R visit(ListSliceExpression expression, T arg) throws CompilationException;
}
diff --git a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/SqlppQueryRewriter.java b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/SqlppQueryRewriter.java
index 5aa5a8c..b785cbd 100644
--- a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/SqlppQueryRewriter.java
+++ b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/SqlppQueryRewriter.java
@@ -49,6 +49,7 @@
import org.apache.asterix.lang.sqlpp.clause.SelectSetOperation;
import org.apache.asterix.lang.sqlpp.clause.UnnestClause;
import org.apache.asterix.lang.sqlpp.expression.CaseExpression;
+import org.apache.asterix.lang.common.expression.ListSliceExpression;
import org.apache.asterix.lang.sqlpp.expression.SelectExpression;
import org.apache.asterix.lang.sqlpp.expression.WindowExpression;
import org.apache.asterix.lang.sqlpp.parser.FunctionParser;
@@ -406,5 +407,16 @@
}
return null;
}
+
+ @Override
+ public Void visit(ListSliceExpression expression, Void arg) throws CompilationException {
+ expression.getExpr().accept(this, arg);
+ expression.getStartIndexExpression().accept(this, arg);
+
+ if (expression.hasEndExpression()) {
+ expression.getEndIndexExpression().accept(this, arg);
+ }
+ return null;
+ }
}
}
\ No newline at end of file
diff --git a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/SqlppInlineUdfsVisitor.java b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/SqlppInlineUdfsVisitor.java
index c9b2dea..0ffb590 100644
--- a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/SqlppInlineUdfsVisitor.java
+++ b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/SqlppInlineUdfsVisitor.java
@@ -43,6 +43,7 @@
import org.apache.asterix.lang.sqlpp.clause.SelectSetOperation;
import org.apache.asterix.lang.sqlpp.clause.UnnestClause;
import org.apache.asterix.lang.sqlpp.expression.CaseExpression;
+import org.apache.asterix.lang.common.expression.ListSliceExpression;
import org.apache.asterix.lang.sqlpp.expression.SelectExpression;
import org.apache.asterix.lang.sqlpp.expression.WindowExpression;
import org.apache.asterix.lang.sqlpp.struct.SetOperationRight;
@@ -260,6 +261,28 @@
return inlined;
}
+ @Override
+ public Boolean visit(ListSliceExpression expression, List<FunctionDecl> funcs) throws CompilationException {
+ Pair<Boolean, Expression> expressionResult = inlineUdfsInExpr(expression.getExpr(), funcs);
+ expression.setExpr(expressionResult.second);
+ boolean inlined = expressionResult.first;
+
+ Pair<Boolean, Expression> startIndexExpressResult =
+ inlineUdfsInExpr(expression.getStartIndexExpression(), funcs);
+ expression.setStartIndexExpression(startIndexExpressResult.second);
+ inlined |= startIndexExpressResult.first;
+
+ // End index expression can be null (optional)
+ if (expression.hasEndExpression()) {
+ Pair<Boolean, Expression> endIndexExpressionResult =
+ inlineUdfsInExpr(expression.getEndIndexExpression(), funcs);
+ expression.setEndIndexExpression(endIndexExpressionResult.second);
+ inlined |= endIndexExpressionResult.first;
+ }
+
+ return inlined;
+ }
+
private Map<Expression, Expression> extractLetBindingVariableExpressionMappings(List<LetClause> letClauses)
throws CompilationException {
Map<Expression, Expression> varExprMap = new HashMap<>();
diff --git a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/CheckDatasetOnlyResolutionVisitor.java b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/CheckDatasetOnlyResolutionVisitor.java
index 42b43e8..a32c54b 100644
--- a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/CheckDatasetOnlyResolutionVisitor.java
+++ b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/CheckDatasetOnlyResolutionVisitor.java
@@ -34,6 +34,7 @@
import org.apache.asterix.lang.common.expression.LiteralExpr;
import org.apache.asterix.lang.common.expression.OperatorExpr;
import org.apache.asterix.lang.common.expression.QuantifiedExpression;
+import org.apache.asterix.lang.common.expression.ListSliceExpression;
import org.apache.asterix.lang.common.expression.RecordConstructor;
import org.apache.asterix.lang.common.expression.UnaryExpr;
import org.apache.asterix.lang.common.expression.VariableExpr;
@@ -109,6 +110,11 @@
}
@Override
+ public Boolean visit(ListSliceExpression expression, ILangExpression expr) throws CompilationException {
+ return false;
+ }
+
+ @Override
public Boolean visit(IfExpr ifexpr, ILangExpression expr) throws CompilationException {
return false;
}
diff --git a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/CheckSql92AggregateVisitor.java b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/CheckSql92AggregateVisitor.java
index daf2ded..6caf0f6 100644
--- a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/CheckSql92AggregateVisitor.java
+++ b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/CheckSql92AggregateVisitor.java
@@ -38,6 +38,7 @@
import org.apache.asterix.lang.common.expression.LiteralExpr;
import org.apache.asterix.lang.common.expression.OperatorExpr;
import org.apache.asterix.lang.common.expression.QuantifiedExpression;
+import org.apache.asterix.lang.common.expression.ListSliceExpression;
import org.apache.asterix.lang.common.expression.RecordConstructor;
import org.apache.asterix.lang.common.expression.UnaryExpr;
import org.apache.asterix.lang.common.expression.VariableExpr;
@@ -130,6 +131,27 @@
}
@Override
+ public Boolean visit(ListSliceExpression expression, ILangExpression parentSelectBlock)
+ throws CompilationException {
+ // Expression
+ if (expression.getExpr().accept(this, parentSelectBlock)) {
+ return true;
+ }
+
+ // Start index expression
+ if (expression.getStartIndexExpression().accept(this, parentSelectBlock)) {
+ return true;
+ }
+
+ // End index expression
+ if (expression.hasEndExpression() && expression.getEndIndexExpression().accept(this, parentSelectBlock)) {
+ return true;
+ }
+
+ return false;
+ }
+
+ @Override
public Boolean visit(IfExpr ifexpr, ILangExpression parentSelectBlock) throws CompilationException {
if (ifexpr.getCondExpr().accept(this, parentSelectBlock)) {
return true;
diff --git a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/CheckSubqueryVisitor.java b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/CheckSubqueryVisitor.java
index 34e918e..e1647ea 100644
--- a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/CheckSubqueryVisitor.java
+++ b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/CheckSubqueryVisitor.java
@@ -39,6 +39,7 @@
import org.apache.asterix.lang.common.expression.LiteralExpr;
import org.apache.asterix.lang.common.expression.OperatorExpr;
import org.apache.asterix.lang.common.expression.QuantifiedExpression;
+import org.apache.asterix.lang.common.expression.ListSliceExpression;
import org.apache.asterix.lang.common.expression.RecordConstructor;
import org.apache.asterix.lang.common.expression.UnaryExpr;
import org.apache.asterix.lang.common.expression.VariableExpr;
@@ -228,6 +229,12 @@
}
@Override
+ public Boolean visit(ListSliceExpression expression, ILangExpression arg) throws CompilationException {
+ return visit(expression.getExpr(), arg) || visit(expression.getStartIndexExpression(), arg)
+ || visit(expression.getEndIndexExpression(), arg);
+ }
+
+ @Override
public Boolean visit(IfExpr ifexpr, ILangExpression arg) throws CompilationException {
return visit(ifexpr.getCondExpr(), arg) || visit(ifexpr.getThenExpr(), arg) || visit(ifexpr.getElseExpr(), arg);
}
diff --git a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/DeepCopyVisitor.java b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/DeepCopyVisitor.java
index 7dca268..90cfab9 100644
--- a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/DeepCopyVisitor.java
+++ b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/DeepCopyVisitor.java
@@ -42,6 +42,7 @@
import org.apache.asterix.lang.common.expression.LiteralExpr;
import org.apache.asterix.lang.common.expression.OperatorExpr;
import org.apache.asterix.lang.common.expression.QuantifiedExpression;
+import org.apache.asterix.lang.common.expression.ListSliceExpression;
import org.apache.asterix.lang.common.expression.RecordConstructor;
import org.apache.asterix.lang.common.expression.UnaryExpr;
import org.apache.asterix.lang.common.expression.VariableExpr;
@@ -485,6 +486,22 @@
}
@Override
+ public Expression visit(ListSliceExpression expression, Void arg) throws CompilationException {
+ Expression expr = (Expression) expression.getExpr().accept(this, arg);
+ Expression startIndexExpression = (Expression) expression.getStartIndexExpression().accept(this, arg);
+
+ // End index expression can be null (optional)
+ Expression endIndexExpression = null;
+ if (expression.hasEndExpression()) {
+ endIndexExpression = (Expression) expression.getEndIndexExpression().accept(this, arg);
+ }
+ ListSliceExpression copy = new ListSliceExpression(expr, startIndexExpression, endIndexExpression);
+ copy.setSourceLocation(expression.getSourceLocation());
+ copy.addHints(expression.getHints());
+ return copy;
+ }
+
+ @Override
public ILangExpression visit(CaseExpression caseExpr, Void arg) throws CompilationException {
Expression conditionExpr = (Expression) caseExpr.getConditionExpr().accept(this, arg);
List<Expression> whenExprList = copyExprList(caseExpr.getWhenExprs(), arg);
diff --git a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/FreeVariableVisitor.java b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/FreeVariableVisitor.java
index 3fb3507..dfa1430 100644
--- a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/FreeVariableVisitor.java
+++ b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/FreeVariableVisitor.java
@@ -40,6 +40,7 @@
import org.apache.asterix.lang.common.expression.LiteralExpr;
import org.apache.asterix.lang.common.expression.OperatorExpr;
import org.apache.asterix.lang.common.expression.QuantifiedExpression;
+import org.apache.asterix.lang.common.expression.ListSliceExpression;
import org.apache.asterix.lang.common.expression.RecordConstructor;
import org.apache.asterix.lang.common.expression.UnaryExpr;
import org.apache.asterix.lang.common.expression.VariableExpr;
@@ -417,6 +418,18 @@
}
@Override
+ public Void visit(ListSliceExpression expression, Collection<VariableExpr> freeVars) throws CompilationException {
+ expression.getExpr().accept(this, freeVars);
+ expression.getStartIndexExpression().accept(this, freeVars);
+
+ // End index expression can be null (optional)
+ if (expression.hasEndExpression()) {
+ expression.getEndIndexExpression().accept(this, freeVars);
+ }
+ return null;
+ }
+
+ @Override
public Void visit(CaseExpression caseExpr, Collection<VariableExpr> freeVars) throws CompilationException {
caseExpr.getConditionExpr().accept(this, freeVars);
visit(caseExpr.getWhenExprs(), freeVars);
diff --git a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/SqlppAstPrintVisitor.java b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/SqlppAstPrintVisitor.java
index e4d2a27..c12914d 100644
--- a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/SqlppAstPrintVisitor.java
+++ b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/SqlppAstPrintVisitor.java
@@ -47,6 +47,7 @@
import org.apache.asterix.lang.sqlpp.clause.SelectSetOperation;
import org.apache.asterix.lang.sqlpp.clause.UnnestClause;
import org.apache.asterix.lang.sqlpp.expression.CaseExpression;
+import org.apache.asterix.lang.common.expression.ListSliceExpression;
import org.apache.asterix.lang.sqlpp.expression.SelectExpression;
import org.apache.asterix.lang.sqlpp.expression.WindowExpression;
import org.apache.asterix.lang.sqlpp.struct.SetOperationRight;
@@ -357,4 +358,22 @@
out.println(skip(step) + ")");
return null;
}
+
+ @Override
+ public Void visit(ListSliceExpression expression, Integer step) throws CompilationException {
+ out.println(skip(step) + "ListSliceExpression [");
+ expression.getExpr().accept(this, step + 1);
+
+ out.print("Start Index: ");
+ expression.getStartIndexExpression().accept(this, step + 1);
+ out.println(skip(step) + ":");
+
+ // End index expression can be null (optional)
+ if (expression.hasEndExpression()) {
+ out.print("End Index: ");
+ expression.getEndIndexExpression().accept(this, step + 1);
+ }
+ out.println(skip(step) + "]");
+ return null;
+ }
}
diff --git a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/base/AbstractSqlppAstVisitor.java b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/base/AbstractSqlppAstVisitor.java
index 92ebd60..e9c0e4c 100644
--- a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/base/AbstractSqlppAstVisitor.java
+++ b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/base/AbstractSqlppAstVisitor.java
@@ -19,6 +19,7 @@
package org.apache.asterix.lang.sqlpp.visitor.base;
import org.apache.asterix.common.exceptions.CompilationException;
+import org.apache.asterix.lang.common.expression.ListSliceExpression;
import org.apache.asterix.lang.common.visitor.base.AbstractAstVisitor;
import org.apache.asterix.lang.sqlpp.clause.FromClause;
import org.apache.asterix.lang.sqlpp.clause.FromTerm;
@@ -115,4 +116,9 @@
public R visit(WindowExpression winExpr, T arg) throws CompilationException {
return null;
}
+
+ @Override
+ public R visit(ListSliceExpression expression, T arg) throws CompilationException {
+ return null;
+ }
}
diff --git a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/base/AbstractSqlppSimpleExpressionVisitor.java b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/base/AbstractSqlppSimpleExpressionVisitor.java
index a3bb592..9454984 100644
--- a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/base/AbstractSqlppSimpleExpressionVisitor.java
+++ b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/base/AbstractSqlppSimpleExpressionVisitor.java
@@ -39,6 +39,7 @@
import org.apache.asterix.lang.common.expression.LiteralExpr;
import org.apache.asterix.lang.common.expression.OperatorExpr;
import org.apache.asterix.lang.common.expression.QuantifiedExpression;
+import org.apache.asterix.lang.common.expression.ListSliceExpression;
import org.apache.asterix.lang.common.expression.RecordConstructor;
import org.apache.asterix.lang.common.expression.UnaryExpr;
import org.apache.asterix.lang.common.expression.VariableExpr;
@@ -347,6 +348,18 @@
}
@Override
+ public Expression visit(ListSliceExpression expression, ILangExpression arg) throws CompilationException {
+ expression.setExpr(visit(expression.getExpr(), expression));
+ expression.setStartIndexExpression(visit(expression.getStartIndexExpression(), arg));
+
+ // End index expression can be null (optional)
+ if (expression.hasEndExpression()) {
+ expression.setEndIndexExpression(visit(expression.getEndIndexExpression(), arg));
+ }
+ return expression;
+ }
+
+ @Override
public Expression visit(CaseExpression caseExpr, ILangExpression arg) throws CompilationException {
caseExpr.setConditionExpr(visit(caseExpr.getConditionExpr(), arg));
caseExpr.setWhenExprs(visit(caseExpr.getWhenExprs(), arg));
diff --git a/asterixdb/asterix-lang-sqlpp/src/main/javacc/SQLPP.jj b/asterixdb/asterix-lang-sqlpp/src/main/javacc/SQLPP.jj
index e19ee7a..19f2cee 100644
--- a/asterixdb/asterix-lang-sqlpp/src/main/javacc/SQLPP.jj
+++ b/asterixdb/asterix-lang-sqlpp/src/main/javacc/SQLPP.jj
@@ -92,6 +92,7 @@
import org.apache.asterix.lang.common.expression.IndexAccessor;
import org.apache.asterix.lang.common.expression.IndexedTypeExpression;
import org.apache.asterix.lang.common.expression.ListConstructor;
+import org.apache.asterix.lang.common.expression.ListSliceExpression;
import org.apache.asterix.lang.common.expression.LiteralExpr;
import org.apache.asterix.lang.common.expression.OperatorExpr;
import org.apache.asterix.lang.common.expression.OrderedListTypeDefinition;
@@ -2293,9 +2294,11 @@
AbstractAccessor accessor = null;
}
{
- expr = PrimaryExpr() (
- accessor = FieldAccessor(accessor != null ? accessor : expr)
- | accessor = IndexAccessor(accessor != null ? accessor : expr)
+ expr = PrimaryExpr()
+ (
+ accessor = FieldAccessor(accessor != null ? accessor : expr)
+ |
+ accessor = IndexAccessor(accessor != null ? accessor : expr)
)*
{
return accessor == null ? expr : accessor;
@@ -2315,30 +2318,52 @@
}
}
-IndexAccessor IndexAccessor(Expression inputExpr) throws ParseException:
+AbstractAccessor IndexAccessor(Expression inputExpr) throws ParseException:
{
Token startToken = null;
- Expression expr = null;
+ boolean isListSliceExpression = false;
+ AbstractAccessor resultExpression = null;
+ Expression argumentExpression1 = null;
+ Expression argumentExpression2 = null;
}
{
<LEFTBRACKET> { startToken = token; }
- ( expr = Expression()
+ ( argumentExpression1 = Expression()
{
- if (expr.getKind() == Expression.Kind.LITERAL_EXPRESSION)
+ if (argumentExpression1.getKind() == Expression.Kind.LITERAL_EXPRESSION)
{
- Literal lit = ((LiteralExpr)expr).getValue();
+ Literal lit = ((LiteralExpr)argumentExpression1).getValue();
if (lit.getLiteralType() != Literal.Type.INTEGER &&
lit.getLiteralType() != Literal.Type.LONG) {
- throw new SqlppParseException(expr.getSourceLocation(), "Index should be an INTEGER");
+ throw new SqlppParseException(argumentExpression1.getSourceLocation(), "Index should be an INTEGER");
}
}
}
)
-
+ (<COLON>
+ {
+ isListSliceExpression = true;
+ }
+ ( argumentExpression2 = Expression()
+ {
+ if (argumentExpression2.getKind() == Expression.Kind.LITERAL_EXPRESSION) {
+ Literal lit = ((LiteralExpr)argumentExpression2).getValue();
+ if (lit.getLiteralType() != Literal.Type.INTEGER &&
+ lit.getLiteralType() != Literal.Type.LONG) {
+ throw new SqlppParseException(argumentExpression2.getSourceLocation(), "Index should be an INTEGER");
+ }
+ }
+ })?
+ )?
<RIGHTBRACKET>
{
- IndexAccessor ia = new IndexAccessor(inputExpr, expr);
- return addSourceLocation(ia, startToken);
+ if (!isListSliceExpression) {
+ resultExpression = new IndexAccessor(inputExpr, argumentExpression1);
+ } else {
+ resultExpression = new ListSliceExpression(inputExpr, argumentExpression1, argumentExpression2);
+ }
+
+ return addSourceLocation(resultExpression, startToken);
}
}
diff --git a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/AbstractArraySliceEval.java b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/AbstractArraySliceEval.java
index 571e4d2..0de4266 100644
--- a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/AbstractArraySliceEval.java
+++ b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/AbstractArraySliceEval.java
@@ -269,8 +269,8 @@
throw new UnsupportedItemTypeException(sourceLoc, functionIdentifier, typeTag.serialize());
}
- // Values like 1, 2, 3.0 are ok, but 0.3 and 3.5 are not accepted
- if (value > Math.floor(value)) {
+ // Values like 1, 2, 3.0 are ok, but 0.3 and 3.5 are not accepted, also handle NaN and INF/-INF
+ if (Double.isNaN(value) || Double.isInfinite(value) || value > Math.floor(value)) {
throw new InvalidDataFormatException(sourceLoc, functionIdentifier, typeTag.serialize());
}