Dmitry Lychagin has submitted this change and it was merged. ( https://asterix-gerrit.ics.uci.edu/3419 )
Change subject: [NO ISSUE][FUN] Support FROM LAST in NTH_VALUE() ...................................................................... [NO ISSUE][FUN] Support FROM LAST in NTH_VALUE() - user model changes: yes - storage format changes: no - interface changes: no Details: - Support FROM FIRST / FROM LAST modifiers in window function NTH_VALUE() with FROM FIRST being the default - Minor cleanup of SQL++ grammar - Update JavaCC version to 6.1.2 Change-Id: Iceac579bd5a3e651bcd7707e324148690e020cf5 Reviewed-on: https://asterix-gerrit.ics.uci.edu/3419 Contrib: Jenkins <jenk...@fulliautomatix.ics.uci.edu> Tested-by: Jenkins <jenk...@fulliautomatix.ics.uci.edu> Integration-Tests: Jenkins <jenk...@fulliautomatix.ics.uci.edu> Reviewed-by: Ali Alsuliman <ali.al.solai...@gmail.com> --- M asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/SqlppExpressionToPlanTranslator.java A asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/window/nth_value_01/nth_value_01.2.query.sqlpp A asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/window/nth_value_01/nth_value_01.3.query.sqlpp A asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/window/nth_value_01/nth_value_01.4.query.sqlpp A asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/window/nth_value_01/nth_value_01.5.query.sqlpp A asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/window/win_negative/win_negative.8.query.sqlpp A asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/window/win_negative/win_negative.9.query.sqlpp A asterixdb/asterix-app/src/test/resources/runtimets/results/window/nth_value_01/nth_value_01.2.adm A asterixdb/asterix-app/src/test/resources/runtimets/results/window/nth_value_01/nth_value_01.3.adm A asterixdb/asterix-app/src/test/resources/runtimets/results/window/nth_value_01/nth_value_01.4.adm A asterixdb/asterix-app/src/test/resources/runtimets/results/window/nth_value_01/nth_value_01.5.adm M asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml M asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/expression/WindowExpression.java M asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/DeepCopyVisitor.java M asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/SqlppCloneAndSubstituteVariablesVisitor.java M asterixdb/asterix-lang-sqlpp/src/main/javacc/SQLPP.jj M asterixdb/asterix-om/src/main/java/org/apache/asterix/om/functions/BuiltinFunctions.java M asterixdb/pom.xml 18 files changed, 341 insertions(+), 28 deletions(-) Approvals: Jenkins: Verified; ; Verified Anon. E. Moose (1000171): Ali Alsuliman: Looks good to me, approved Objections: Jenkins: Violations found diff --git a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/SqlppExpressionToPlanTranslator.java b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/SqlppExpressionToPlanTranslator.java index 9ba6d2c..988723f 100644 --- a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/SqlppExpressionToPlanTranslator.java +++ b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/SqlppExpressionToPlanTranslator.java @@ -1058,6 +1058,8 @@ BuiltinFunctions.WindowFunctionProperty.NO_FRAME_CLAUSE); boolean allowRespectIgnoreNulls = isWin && BuiltinFunctions.builtinFunctionHasProperty(fi, BuiltinFunctions.WindowFunctionProperty.ALLOW_RESPECT_IGNORE_NULLS); + boolean allowFromFirstLast = isWin && BuiltinFunctions.builtinFunctionHasProperty(fi, + BuiltinFunctions.WindowFunctionProperty.ALLOW_FROM_FIRST_LAST); Mutable<ILogicalOperator> currentOpRef = tupSource; @@ -1138,6 +1140,8 @@ boolean respectNulls = !getBooleanModifier(winExpr.getIgnoreNulls(), false, allowRespectIgnoreNulls, sourceLoc, "RESPECT/IGNORE NULLS", fs.getName()); + boolean fromLast = getBooleanModifier(winExpr.getFromLast(), false, allowFromFirstLast, sourceLoc, + "FROM FIRST/LAST", fs.getName()); boolean makeRunningAgg = false, makeNestedAgg = false; FunctionIdentifier runningAggFunc = null, nestedAggFunc = null, winResultFunc = null, postWinResultFunc = null; @@ -1174,9 +1178,7 @@ // IGNORE NULLS if (isLag) { // reverse order for LAG() - for (Pair<OrderOperator.IOrder, Mutable<ILogicalExpression>> orderExprPair : orderExprListOut) { - orderExprPair.setFirst(reverseOrder(orderExprPair.getFirst())); - } + reverseOrder(orderExprListOut); } winFrameStartKind = WindowExpression.FrameBoundaryKind.BOUNDED_FOLLOWING; winFrameStartExpr = new LiteralExpr(new IntegerLiteral(1)); @@ -1212,6 +1214,10 @@ } } else if (BuiltinFunctions.NTH_VALUE_IMPL.equals(fi)) { nestedAggFunc = BuiltinFunctions.SCALAR_FIRST_ELEMENT; + if (fromLast) { + // reverse order if FROM LAST modifier is present + reverseOrder(orderExprListOut); + } if (respectNulls) { winFrameMaxOjbects = 1; } else { @@ -1690,6 +1696,13 @@ return opExpr; } + private static void reverseOrder(List<Pair<OrderOperator.IOrder, Mutable<ILogicalExpression>>> orderExprList) + throws CompilationException { + for (Pair<OrderOperator.IOrder, Mutable<ILogicalExpression>> orderExprPair : orderExprList) { + orderExprPair.setFirst(reverseOrder(orderExprPair.getFirst())); + } + } + private static OrderOperator.IOrder reverseOrder(OrderOperator.IOrder order) throws CompilationException { switch (order.getKind()) { case ASC: diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/window/nth_value_01/nth_value_01.2.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/window/nth_value_01/nth_value_01.2.query.sqlpp new file mode 100644 index 0000000..5d7ed88 --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/window/nth_value_01/nth_value_01.2.query.sqlpp @@ -0,0 +1,43 @@ +/* + * 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. + */ +/* + * Description : NTH_VALUE() FROM FIRST (default), RESPECT/IGNORE NULLS + * Expected Res : SUCCESS + */ + +from [ + { "x": "a", "y": 1, "p": 0 }, + { "y": 2, "p": 0 }, + { "x": null, "y": 3, "p": 0 }, + { "x": "b", "y": 4, "p": 0 }, + + { "x": "a", "y": 5, "p": 1 }, + { "x": null, "y": 6, "p": 1 }, + { "y": 7, "p": 1 }, + { "x": "b", "y": 8, "p": 1 } +] t +select + nth_value(x, 2) from first over (partition by p order by y range between unbounded preceding and unbounded following) + as nth_value_default_respect, + nth_value(x, 2) from first RESPECT NULLS over (partition by p order by y range between unbounded preceding and unbounded following) + as nth_value_respect, + nth_value(x, 2) FROM FIRST IGNORE NULLS over (partition by p order by y range between unbounded preceding and unbounded following) + as nth_value_ignore, + x, y, p +order by y \ No newline at end of file diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/window/nth_value_01/nth_value_01.3.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/window/nth_value_01/nth_value_01.3.query.sqlpp new file mode 100644 index 0000000..51f315e --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/window/nth_value_01/nth_value_01.3.query.sqlpp @@ -0,0 +1,43 @@ +/* + * 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. + */ +/* + * Description : NTH_VALUE() FROM LAST, RESPECT/IGNORE NULLS + * Expected Res : SUCCESS + */ + +from [ + { "x": "a", "y": 1, "p": 0 }, + { "y": 2, "p": 0 }, + { "x": null, "y": 3, "p": 0 }, + { "x": "b", "y": 4, "p": 0 }, + + { "x": "a", "y": 5, "p": 1 }, + { "x": null, "y": 6, "p": 1 }, + { "y": 7, "p": 1 }, + { "x": "b", "y": 8, "p": 1 } +] t +select + nth_value(x, 2) from last over (partition by p order by y range between unbounded preceding and unbounded following) + as nth_value_default_respect, + nth_value(x, 2) from last RESPECT NULLS over (partition by p order by y range between unbounded preceding and unbounded following) + as nth_value_respect, + nth_value(x, 2) FROM LAST IGNORE NULLS over (partition by p order by y range between unbounded preceding and unbounded following) + as nth_value_ignore, + x, y, p +order by y \ No newline at end of file diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/window/nth_value_01/nth_value_01.4.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/window/nth_value_01/nth_value_01.4.query.sqlpp new file mode 100644 index 0000000..e17155a --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/window/nth_value_01/nth_value_01.4.query.sqlpp @@ -0,0 +1,46 @@ +/* + * 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. + */ +/* + * Description : NTH_VALUE() FROM FIRST/LAST, RESPECT/IGNORE NULLS + * : that exceeds frame boundary + * Expected Res : SUCCESS + */ + +from [ + { "x": "a", "y": 1, "p": 0 }, + { "y": 2, "p": 0 }, + { "x": null, "y": 3, "p": 0 }, + { "x": "b", "y": 4, "p": 0 }, + + { "x": "a", "y": 5, "p": 1 }, + { "x": null, "y": 6, "p": 1 }, + { "y": 7, "p": 1 }, + { "x": "b", "y": 8, "p": 1 } +] t +select + nth_value(x, 5) from first respect nulls over (partition by p order by y range between unbounded preceding and unbounded following) + as nth_value_first_respect, + nth_value(x, 3) from first ignore nulls over (partition by p order by y range between unbounded preceding and unbounded following) + as nth_value_first_ignore, + nth_value(x, 5) from last respect nulls over (partition by p order by y range between unbounded preceding and unbounded following) + as nth_value_last_respect, + nth_value(x, 3) from last ignore nulls over (partition by p order by y range between unbounded preceding and unbounded following) + as nth_value_last_ignore, + x, y, p +order by y \ No newline at end of file diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/window/nth_value_01/nth_value_01.5.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/window/nth_value_01/nth_value_01.5.query.sqlpp new file mode 100644 index 0000000..7c62cdb --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/window/nth_value_01/nth_value_01.5.query.sqlpp @@ -0,0 +1,28 @@ +/* + * 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. + */ +/* + * Description : Test FROM FIRST/LAST outside of a window function call + * Expected Res : SUCCESS + */ + +with first as [1, 2, 3], last as [1, 2, 1, 2] +select count(`over`) c, sum(`over`) from first `over` +union all +select count(`over`) c, sum(`over`) from last `over` +order by c diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/window/win_negative/win_negative.8.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/window/win_negative/win_negative.8.query.sqlpp new file mode 100644 index 0000000..73344ce --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/window/win_negative/win_negative.8.query.sqlpp @@ -0,0 +1,25 @@ +/* + * 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. + */ +/* + * Description : Function that doesn't support FROM FIRST/LAST + * Expected Res : FAILURE + */ + +from range(1, 4) x +select value first_value(x) from first over (order by x) \ No newline at end of file diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/window/win_negative/win_negative.9.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/window/win_negative/win_negative.9.query.sqlpp new file mode 100644 index 0000000..c03e763 --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/window/win_negative/win_negative.9.query.sqlpp @@ -0,0 +1,25 @@ +/* + * 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. + */ +/* + * Description : Function that doesn't support FROM FIRST/LAST + * Expected Res : FAILURE + */ + +from range(1, 4) x +select value first_value(x) from last over (order by x) \ No newline at end of file diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/window/nth_value_01/nth_value_01.2.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/window/nth_value_01/nth_value_01.2.adm new file mode 100644 index 0000000..55ac6c6 --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/window/nth_value_01/nth_value_01.2.adm @@ -0,0 +1,8 @@ +{ "nth_value_ignore": "b", "x": "a", "y": 1, "p": 0 } +{ "nth_value_ignore": "b", "y": 2, "p": 0 } +{ "nth_value_ignore": "b", "x": null, "y": 3, "p": 0 } +{ "nth_value_ignore": "b", "x": "b", "y": 4, "p": 0 } +{ "nth_value_default_respect": null, "nth_value_respect": null, "nth_value_ignore": "b", "x": "a", "y": 5, "p": 1 } +{ "nth_value_default_respect": null, "nth_value_respect": null, "nth_value_ignore": "b", "x": null, "y": 6, "p": 1 } +{ "nth_value_default_respect": null, "nth_value_respect": null, "nth_value_ignore": "b", "y": 7, "p": 1 } +{ "nth_value_default_respect": null, "nth_value_respect": null, "nth_value_ignore": "b", "x": "b", "y": 8, "p": 1 } \ No newline at end of file diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/window/nth_value_01/nth_value_01.3.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/window/nth_value_01/nth_value_01.3.adm new file mode 100644 index 0000000..7ccb3f9 --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/window/nth_value_01/nth_value_01.3.adm @@ -0,0 +1,8 @@ +{ "nth_value_default_respect": null, "nth_value_respect": null, "nth_value_ignore": "a", "x": "a", "y": 1, "p": 0 } +{ "nth_value_default_respect": null, "nth_value_respect": null, "nth_value_ignore": "a", "y": 2, "p": 0 } +{ "nth_value_default_respect": null, "nth_value_respect": null, "nth_value_ignore": "a", "x": null, "y": 3, "p": 0 } +{ "nth_value_default_respect": null, "nth_value_respect": null, "nth_value_ignore": "a", "x": "b", "y": 4, "p": 0 } +{ "nth_value_ignore": "a", "x": "a", "y": 5, "p": 1 } +{ "nth_value_ignore": "a", "x": null, "y": 6, "p": 1 } +{ "nth_value_ignore": "a", "y": 7, "p": 1 } +{ "nth_value_ignore": "a", "x": "b", "y": 8, "p": 1 } \ No newline at end of file diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/window/nth_value_01/nth_value_01.4.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/window/nth_value_01/nth_value_01.4.adm new file mode 100644 index 0000000..4faf9b1 --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/window/nth_value_01/nth_value_01.4.adm @@ -0,0 +1,8 @@ +{ "nth_value_first_respect": null, "nth_value_first_ignore": null, "nth_value_last_respect": null, "nth_value_last_ignore": null, "x": "a", "y": 1, "p": 0 } +{ "nth_value_first_respect": null, "nth_value_first_ignore": null, "nth_value_last_respect": null, "nth_value_last_ignore": null, "y": 2, "p": 0 } +{ "nth_value_first_respect": null, "nth_value_first_ignore": null, "nth_value_last_respect": null, "nth_value_last_ignore": null, "x": null, "y": 3, "p": 0 } +{ "nth_value_first_respect": null, "nth_value_first_ignore": null, "nth_value_last_respect": null, "nth_value_last_ignore": null, "x": "b", "y": 4, "p": 0 } +{ "nth_value_first_respect": null, "nth_value_first_ignore": null, "nth_value_last_respect": null, "nth_value_last_ignore": null, "x": "a", "y": 5, "p": 1 } +{ "nth_value_first_respect": null, "nth_value_first_ignore": null, "nth_value_last_respect": null, "nth_value_last_ignore": null, "x": null, "y": 6, "p": 1 } +{ "nth_value_first_respect": null, "nth_value_first_ignore": null, "nth_value_last_respect": null, "nth_value_last_ignore": null, "y": 7, "p": 1 } +{ "nth_value_first_respect": null, "nth_value_first_ignore": null, "nth_value_last_respect": null, "nth_value_last_ignore": null, "x": "b", "y": 8, "p": 1 } \ No newline at end of file diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/window/nth_value_01/nth_value_01.5.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/window/nth_value_01/nth_value_01.5.adm new file mode 100644 index 0000000..e062cda --- /dev/null +++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/window/nth_value_01/nth_value_01.5.adm @@ -0,0 +1,2 @@ +{ "c": 3, "$1": 6 } +{ "c": 4, "$2": 6 } \ No newline at end of file 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 d5fa013..d1098dc 100644 --- a/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml +++ b/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml @@ -10424,6 +10424,8 @@ <expected-error>ASX1079: Compilation error: count is a SQL-92 aggregate function</expected-error> <expected-error>ASX1104: Invalid modifier RESPECT/IGNORE NULLS for function</expected-error> <expected-error>ASX1104: Invalid modifier RESPECT/IGNORE NULLS for function</expected-error> + <expected-error>ASX1104: Invalid modifier FROM FIRST/LAST for function</expected-error> + <expected-error>ASX1104: Invalid modifier FROM FIRST/LAST for function</expected-error> <source-location>false</source-location> </compilation-unit> </test-case> diff --git a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/expression/WindowExpression.java b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/expression/WindowExpression.java index 5a9173b..e0a6c6b 100644 --- a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/expression/WindowExpression.java +++ b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/expression/WindowExpression.java @@ -55,13 +55,14 @@ private List<Pair<Expression, Identifier>> windowFieldList; private Boolean ignoreNulls; + private Boolean fromLast; public WindowExpression(FunctionSignature functionSignature, List<Expression> exprList, List<Expression> partitionList, List<Expression> orderbyList, List<OrderbyClause.OrderModifier> orderbyModifierList, FrameMode frameMode, FrameBoundaryKind frameStartKind, Expression frameStartExpr, FrameBoundaryKind frameEndKind, Expression frameEndExpr, FrameExclusionKind frameExclusionKind, VariableExpr windowVar, - List<Pair<Expression, Identifier>> windowFieldList, Boolean ignoreNulls) { + List<Pair<Expression, Identifier>> windowFieldList, Boolean ignoreNulls, Boolean fromLast) { if (functionSignature == null || exprList == null) { throw new NullPointerException(); } @@ -79,6 +80,7 @@ this.windowVar = windowVar; this.windowFieldList = windowFieldList; this.ignoreNulls = ignoreNulls; + this.fromLast = fromLast; } @Override @@ -232,12 +234,20 @@ this.ignoreNulls = ignoreNulls; } + public Boolean getFromLast() { + return fromLast; + } + + public void setFromLast(Boolean fromLast) { + this.fromLast = fromLast; + } + @Override public int hashCode() { return Objects.hash(functionSignature, exprList, ExpressionUtils.emptyIfNull(partitionList), ExpressionUtils.emptyIfNull(orderbyList), ExpressionUtils.emptyIfNull(orderbyModifierList), frameMode, frameStartKind, frameStartExpr, frameEndKind, frameEndExpr, frameExclusionKind, windowVar, - ExpressionUtils.emptyIfNull(windowFieldList), ignoreNulls); + ExpressionUtils.emptyIfNull(windowFieldList), ignoreNulls, fromLast); } @Override @@ -263,7 +273,7 @@ && Objects.equals(windowVar, target.windowVar) && Objects.equals(ExpressionUtils.emptyIfNull(windowFieldList), ExpressionUtils.emptyIfNull(target.windowFieldList)) - && Objects.equals(ignoreNulls, target.ignoreNulls); + && Objects.equals(ignoreNulls, target.ignoreNulls) && Objects.equals(fromLast, target.fromLast); } @Override @@ -274,6 +284,9 @@ sb.append('('); sb.append(StringUtils.join(exprList, ',')); sb.append(')'); + if (fromLast != null && fromLast) { + sb.append(" FROM LAST"); + } if (ignoreNulls != null && ignoreNulls) { sb.append(" IGNORE NULLS"); } 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 3e07177..6e28d36 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 @@ -525,7 +525,7 @@ WindowExpression copy = new WindowExpression(winExpr.getFunctionSignature(), newExprList, newPartitionList, newOrderbyList, newOrderbyModifierList, winExpr.getFrameMode(), winExpr.getFrameStartKind(), newFrameStartExpr, winExpr.getFrameEndKind(), newFrameEndExpr, winExpr.getFrameExclusionKind(), - newWindowVar, newWindowFieldList, winExpr.getIgnoreNulls()); + newWindowVar, newWindowFieldList, winExpr.getIgnoreNulls(), winExpr.getFromLast()); copy.setSourceLocation(winExpr.getSourceLocation()); copy.addHints(winExpr.getHints()); return copy; diff --git a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/SqlppCloneAndSubstituteVariablesVisitor.java b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/SqlppCloneAndSubstituteVariablesVisitor.java index 4b76b56..20fd0f5 100644 --- a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/SqlppCloneAndSubstituteVariablesVisitor.java +++ b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/SqlppCloneAndSubstituteVariablesVisitor.java @@ -420,10 +420,11 @@ winExpr.hasWindowVar() ? (VariableExpr) winExpr.getWindowVar().accept(this, env).first : null; List<Pair<Expression, Identifier>> newWindowFieldList = winExpr.hasWindowFieldList() ? VariableCloneAndSubstitutionUtil.substInFieldList(winExpr.getWindowFieldList(), env, this) : null; - WindowExpression newWinExpr = new WindowExpression(winExpr.getFunctionSignature(), newExprList, - newPartitionList, newOrderbyList, newOrderbyModifierList, winExpr.getFrameMode(), - winExpr.getFrameStartKind(), newFrameStartExpr, winExpr.getFrameEndKind(), newFrameEndExpr, - winExpr.getFrameExclusionKind(), newWindowVar, newWindowFieldList, winExpr.getIgnoreNulls()); + WindowExpression newWinExpr = + new WindowExpression(winExpr.getFunctionSignature(), newExprList, newPartitionList, newOrderbyList, + newOrderbyModifierList, winExpr.getFrameMode(), winExpr.getFrameStartKind(), newFrameStartExpr, + winExpr.getFrameEndKind(), newFrameEndExpr, winExpr.getFrameExclusionKind(), newWindowVar, + newWindowFieldList, winExpr.getIgnoreNulls(), winExpr.getFromLast()); newWinExpr.setSourceLocation(winExpr.getSourceLocation()); newWinExpr.addHints(winExpr.getHints()); return new Pair<>(newWinExpr, env); diff --git a/asterixdb/asterix-lang-sqlpp/src/main/javacc/SQLPP.jj b/asterixdb/asterix-lang-sqlpp/src/main/javacc/SQLPP.jj index c0f1725..25ad2ab 100644 --- a/asterixdb/asterix-lang-sqlpp/src/main/javacc/SQLPP.jj +++ b/asterixdb/asterix-lang-sqlpp/src/main/javacc/SQLPP.jj @@ -191,9 +191,11 @@ // tokens parsed as identifiers private static final String CURRENT = "CURRENT"; private static final String EXCLUDE = "EXCLUDE"; + private static final String FIRST = "FIRST"; private static final String FOLLOWING = "FOLLOWING"; private static final String GROUPS = "GROUPS"; private static final String IGNORE = "IGNORE"; + private static final String LAST = "LAST"; private static final String NO = "NO"; private static final String NULLS = "NULLS"; private static final String OTHERS = "OTHERS"; @@ -1973,7 +1975,7 @@ Token startToken = null; } { - (<NOT> { not = true; startToken = token; } )? inputExpr = RelExpr() + (LOOKAHEAD(2) <NOT> { not = true; startToken = token; } )? inputExpr = RelExpr() { if(not) { FunctionSignature signature = new FunctionSignature(BuiltinFunctions.NOT); @@ -2749,14 +2751,60 @@ resultExpr = callExpr; } - ( resultExpr = WindowExpr(callExpr.getFunctionSignature(), callExpr.getExprList(), token) )? + ( LOOKAHEAD(5) resultExpr = WindowExpr(callExpr.getFunctionSignature(), callExpr.getExprList()) )? { return resultExpr; } } -WindowExpression WindowExpr(FunctionSignature signature, List<Expression> argList, Token startToken) throws ParseException: +WindowExpression WindowExpr(FunctionSignature signature, List<Expression> argList) throws ParseException: +{ + Boolean fromLast = null, ignoreNulls = null; +} +{ + ( + // FROM ( FIRST | LAST ) ( ( RESPECT | IGNORE ) NULLS )? OVER + LOOKAHEAD(5, <FROM> <IDENTIFIER> ( <IDENTIFIER> <IDENTIFIER> )? <OVER>) + <FROM> <IDENTIFIER> + { + if (isToken(FIRST)) { + fromLast = false; + } else if (isToken(LAST)) { + fromLast = true; + } else { + throw createUnexpectedTokenError(); + } + } + )? + ( + // ( RESPECT | IGNORE ) NULLS OVER + LOOKAHEAD(3, <IDENTIFIER> <IDENTIFIER> <OVER>) + <IDENTIFIER> + { + if (isToken(RESPECT)) { + ignoreNulls = false; + } else if (isToken(IGNORE)) { + ignoreNulls = true; + } else { + throw createUnexpectedTokenError(); + } + } + <IDENTIFIER> + { + if (!isToken(NULLS)) { + throw createUnexpectedTokenError(); + } + } + )? + <OVER> + { + return OverClause(signature, argList, token, fromLast, ignoreNulls); + } +} + +WindowExpression OverClause(FunctionSignature signature, List<Expression> argList, Token startToken, Boolean fromLast, + Boolean ignoreNulls) throws ParseException: { Expression partitionExpr = null; List<Expression> partitionExprs = new ArrayList<Expression>(); @@ -2771,17 +2819,8 @@ Pair<VariableExpr, List<Pair<Expression, Identifier>>> windowVarWithFieldList = null; VariableExpr windowVar = null; List<Pair<Expression, Identifier>> windowFieldList = null; - Boolean ignoreNulls = null; } { - ( - ( - LOOKAHEAD({ laIdentifier(RESPECT) }) <IDENTIFIER> { ignoreNulls = false; } - | LOOKAHEAD({ laIdentifier(IGNORE) }) <IDENTIFIER> { ignoreNulls = true; } - ) - LOOKAHEAD({ laIdentifier(NULLS) }) <IDENTIFIER> - )? - <OVER> ( windowVarWithFieldList = VariableWithFieldMap() <AS> { @@ -2827,7 +2866,7 @@ { WindowExpression winExp = new WindowExpression(signature, argList, partitionExprs, orderbyList, orderbyModifierList, frameMode, frameStartKind, frameStartExpr, frameEndKind, frameEndExpr, frameExclusionKind, windowVar, - windowFieldList, ignoreNulls); + windowFieldList, ignoreNulls, fromLast); return addSourceLocation(winExp, startToken); } } @@ -2857,8 +2896,7 @@ } { ( - LOOKAHEAD({ laIdentifier(CURRENT) }) <IDENTIFIER> { current = true; } - | LOOKAHEAD({ laIdentifier(UNBOUNDED) }) <IDENTIFIER> + LOOKAHEAD({ laIdentifier(CURRENT) || laIdentifier(UNBOUNDED) }) <IDENTIFIER> { current = isToken(CURRENT); } | expr = Expression() ) <IDENTIFIER> diff --git a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/functions/BuiltinFunctions.java b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/functions/BuiltinFunctions.java index 3bf3514..06dcb89 100644 --- a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/functions/BuiltinFunctions.java +++ b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/functions/BuiltinFunctions.java @@ -18,6 +18,7 @@ */ package org.apache.asterix.om.functions; +import static org.apache.asterix.om.functions.BuiltinFunctions.WindowFunctionProperty.ALLOW_FROM_FIRST_LAST; import static org.apache.asterix.om.functions.BuiltinFunctions.WindowFunctionProperty.ALLOW_RESPECT_IGNORE_NULLS; import static org.apache.asterix.om.functions.BuiltinFunctions.WindowFunctionProperty.HAS_LIST_ARG; import static org.apache.asterix.om.functions.BuiltinFunctions.WindowFunctionProperty.INJECT_ORDER_ARGS; @@ -3030,8 +3031,10 @@ INJECT_ORDER_ARGS, /** Whether a running aggregate requires partition materialization runtime */ MATERIALIZE_PARTITION, + /** Whether FROM (FIRST | LAST) modifier is allowed */ + ALLOW_FROM_FIRST_LAST, /** Whether (RESPECT | IGNORE) NULLS modifier is allowed */ - ALLOW_RESPECT_IGNORE_NULLS, + ALLOW_RESPECT_IGNORE_NULLS } static { @@ -3042,7 +3045,7 @@ addWindowFunction(LAG, LAG_IMPL, NO_FRAME_CLAUSE, HAS_LIST_ARG, ALLOW_RESPECT_IGNORE_NULLS); addWindowFunction(LAST_VALUE, LAST_VALUE_IMPL, HAS_LIST_ARG, ALLOW_RESPECT_IGNORE_NULLS); addWindowFunction(LEAD, LEAD_IMPL, NO_FRAME_CLAUSE, HAS_LIST_ARG, ALLOW_RESPECT_IGNORE_NULLS); - addWindowFunction(NTH_VALUE, NTH_VALUE_IMPL, HAS_LIST_ARG, ALLOW_RESPECT_IGNORE_NULLS); + addWindowFunction(NTH_VALUE, NTH_VALUE_IMPL, HAS_LIST_ARG, ALLOW_FROM_FIRST_LAST, ALLOW_RESPECT_IGNORE_NULLS); addWindowFunction(NTILE, NTILE_IMPL, NO_FRAME_CLAUSE, MATERIALIZE_PARTITION); addWindowFunction(PERCENT_RANK, PERCENT_RANK_IMPL, NO_FRAME_CLAUSE, INJECT_ORDER_ARGS, MATERIALIZE_PARTITION); addWindowFunction(RANK, RANK_IMPL, NO_FRAME_CLAUSE, INJECT_ORDER_ARGS); diff --git a/asterixdb/pom.xml b/asterixdb/pom.xml index 3e65e5f..0149810 100644 --- a/asterixdb/pom.xml +++ b/asterixdb/pom.xml @@ -568,6 +568,13 @@ <groupId>org.codehaus.mojo</groupId> <artifactId>javacc-maven-plugin</artifactId> <version>2.6</version> + <dependencies> + <dependency> + <groupId>net.java.dev.javacc</groupId> + <artifactId>javacc</artifactId> + <version>6.1.2</version> + </dependency> + </dependencies> </plugin> <plugin> <groupId>net.revelc.code.formatter</groupId> -- To view, visit https://asterix-gerrit.ics.uci.edu/3419 To unsubscribe, visit https://asterix-gerrit.ics.uci.edu/settings Gerrit-Project: asterixdb Gerrit-Branch: master Gerrit-MessageType: merged Gerrit-Change-Id: Iceac579bd5a3e651bcd7707e324148690e020cf5 Gerrit-Change-Number: 3419 Gerrit-PatchSet: 3 Gerrit-Owner: Dmitry Lychagin <dmitry.lycha...@couchbase.com> Gerrit-Reviewer: Ali Alsuliman <ali.al.solai...@gmail.com> Gerrit-Reviewer: Anon. E. Moose (1000171) Gerrit-Reviewer: Dmitry Lychagin <dmitry.lycha...@couchbase.com> Gerrit-Reviewer: Jenkins <jenk...@fulliautomatix.ics.uci.edu> Gerrit-Reviewer: Till Westmann <ti...@apache.org>