http://git-wip-us.apache.org/repos/asf/asterixdb/blob/f2c18aa9/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/AbstractSqlppExpressionExtractionVisitor.java ---------------------------------------------------------------------- diff --git a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/AbstractSqlppExpressionExtractionVisitor.java b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/AbstractSqlppExpressionExtractionVisitor.java new file mode 100644 index 0000000..b78cd9c --- /dev/null +++ b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/AbstractSqlppExpressionExtractionVisitor.java @@ -0,0 +1,149 @@ +/* + * 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.sqlpp.rewrites.visitor; + +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.Deque; +import java.util.List; + +import org.apache.asterix.common.exceptions.CompilationException; +import org.apache.asterix.common.exceptions.ErrorCode; +import org.apache.asterix.lang.common.base.Expression; +import org.apache.asterix.lang.common.base.ILangExpression; +import org.apache.asterix.lang.common.clause.LetClause; +import org.apache.asterix.lang.common.expression.VariableExpr; +import org.apache.asterix.lang.common.rewrites.LangRewritingContext; +import org.apache.asterix.lang.common.struct.VarIdentifier; +import org.apache.asterix.lang.sqlpp.clause.FromClause; +import org.apache.asterix.lang.sqlpp.clause.SelectBlock; +import org.apache.asterix.lang.sqlpp.visitor.base.AbstractSqlppSimpleExpressionVisitor; +import org.apache.hyracks.algebricks.common.utils.Pair; +import org.apache.hyracks.api.exceptions.SourceLocation; + +/** + * Base class for visitors that extract expressions into LET clauses. + * Subclasses should call {@link #extractExpressions(List, int, SourceLocation)} to perform the extraction. + */ +abstract class AbstractSqlppExpressionExtractionVisitor extends AbstractSqlppSimpleExpressionVisitor { + + protected final LangRewritingContext context; + + private final Deque<List<Pair<Expression, VarIdentifier>>> stack = new ArrayDeque<>(); + + AbstractSqlppExpressionExtractionVisitor(LangRewritingContext context) { + this.context = context; + } + + @Override + public Expression visit(SelectBlock selectBlock, ILangExpression arg) throws CompilationException { + List<Pair<Expression, VarIdentifier>> extractionList = new ArrayList<>(); + stack.push(extractionList); + + if (selectBlock.hasFromClause()) { + FromClause clause = selectBlock.getFromClause(); + clause.accept(this, arg); + if (!extractionList.isEmpty()) { + handleUnsupportedClause(clause, extractionList); + } + } + List<LetClause> letList = selectBlock.getLetList(); + if (selectBlock.hasLetClauses()) { + visitLetClauses(letList, extractionList, arg); + } + if (selectBlock.hasWhereClause()) { + selectBlock.getWhereClause().accept(this, arg); + introduceLetClauses(extractionList, letList); + } + if (selectBlock.hasGroupbyClause()) { + selectBlock.getGroupbyClause().accept(this, arg); + introduceLetClauses(extractionList, letList); + } + List<LetClause> letListAfterGby = selectBlock.getLetListAfterGroupby(); + if (selectBlock.hasLetClausesAfterGroupby()) { + visitLetClauses(letListAfterGby, extractionList, arg); + } + if (selectBlock.hasHavingClause()) { + selectBlock.getHavingClause().accept(this, arg); + introduceLetClauses(extractionList, letListAfterGby); + } + selectBlock.getSelectClause().accept(this, arg); + introduceLetClauses(extractionList, selectBlock.hasGroupbyClause() ? letListAfterGby : letList); + + stack.pop(); + return null; + } + + private void visitLetClauses(List<LetClause> letList, List<Pair<Expression, VarIdentifier>> extractionList, + ILangExpression arg) throws CompilationException { + List<LetClause> newLetList = new ArrayList<>(letList.size()); + for (LetClause letClause : letList) { + letClause.accept(this, arg); + introduceLetClauses(extractionList, newLetList); + newLetList.add(letClause); + } + if (newLetList.size() > letList.size()) { + letList.clear(); + letList.addAll(newLetList); + } + } + + private void introduceLetClauses(List<Pair<Expression, VarIdentifier>> fromBindingList, List<LetClause> toLetList) { + for (Pair<Expression, VarIdentifier> p : fromBindingList) { + Expression bindExpr = p.first; + VarIdentifier var = p.second; + VariableExpr varExpr = new VariableExpr(var); + varExpr.setSourceLocation(bindExpr.getSourceLocation()); + toLetList.add(new LetClause(varExpr, bindExpr)); + context.addExcludedForFieldAccessVar(var); + } + fromBindingList.clear(); + } + + List<Expression> extractExpressions(List<Expression> exprList, int limit, SourceLocation sourceLocation) + throws CompilationException { + List<Pair<Expression, VarIdentifier>> outLetList = stack.peek(); + if (outLetList == null) { + throw new CompilationException(ErrorCode.COMPILATION_ERROR, sourceLocation); + } + int n = exprList.size(); + List<Expression> newExprList = new ArrayList<>(n); + for (int i = 0; i < n; i++) { + Expression expr = exprList.get(i); + Expression newExpr; + if (i < limit && isExtractableExpression(expr)) { + VarIdentifier v = context.newVariable(); + VariableExpr vExpr = new VariableExpr(v); + vExpr.setSourceLocation(expr.getSourceLocation()); + outLetList.add(new Pair<>(expr, v)); + newExpr = vExpr; + } else { + newExpr = expr; + } + newExprList.add(newExpr); + } + return newExprList; + } + + abstract boolean isExtractableExpression(Expression expr); + + abstract void handleUnsupportedClause(FromClause clause, List<Pair<Expression, VarIdentifier>> extractionList) + throws CompilationException; +}
http://git-wip-us.apache.org/repos/asf/asterixdb/blob/f2c18aa9/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/Sql92AggregateFunctionVisitor.java ---------------------------------------------------------------------- diff --git a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/Sql92AggregateFunctionVisitor.java b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/Sql92AggregateFunctionVisitor.java new file mode 100644 index 0000000..2be752d --- /dev/null +++ b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/Sql92AggregateFunctionVisitor.java @@ -0,0 +1,176 @@ +/* + * 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.sqlpp.rewrites.visitor; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.apache.asterix.common.exceptions.CompilationException; +import org.apache.asterix.common.exceptions.ErrorCode; +import org.apache.asterix.common.functions.FunctionSignature; +import org.apache.asterix.lang.common.base.Expression; +import org.apache.asterix.lang.common.base.ILangExpression; +import org.apache.asterix.lang.common.expression.CallExpr; +import org.apache.asterix.lang.common.expression.FieldAccessor; +import org.apache.asterix.lang.common.expression.VariableExpr; +import org.apache.asterix.lang.common.rewrites.LangRewritingContext; +import org.apache.asterix.lang.common.struct.Identifier; +import org.apache.asterix.lang.common.struct.VarIdentifier; +import org.apache.asterix.lang.sqlpp.clause.FromClause; +import org.apache.asterix.lang.sqlpp.clause.FromTerm; +import org.apache.asterix.lang.sqlpp.clause.SelectBlock; +import org.apache.asterix.lang.sqlpp.clause.SelectClause; +import org.apache.asterix.lang.sqlpp.clause.SelectElement; +import org.apache.asterix.lang.sqlpp.clause.SelectSetOperation; +import org.apache.asterix.lang.sqlpp.expression.SelectExpression; +import org.apache.asterix.lang.sqlpp.struct.SetOperationInput; +import org.apache.asterix.lang.sqlpp.util.FunctionMapUtil; +import org.apache.asterix.lang.sqlpp.util.SqlppRewriteUtil; +import org.apache.asterix.lang.sqlpp.util.SqlppVariableUtil; +import org.apache.asterix.lang.sqlpp.visitor.base.AbstractSqlppSimpleExpressionVisitor; +import org.apache.hyracks.api.exceptions.SourceLocation; + +/** + * Rewrites SQL-92 aggregate function into a SQL++ core aggregate function. <br/> + * For example + * <code>SUM(e.salary + i.bonus)</code> + * is turned into + * <code>array_sum( (FROM g AS gi SELECT ELEMENT gi.e.salary + gi.i.bonus) )</code> + * where <code>g</code> is a 'group as' variable + */ +class Sql92AggregateFunctionVisitor extends AbstractSqlppSimpleExpressionVisitor { + + private final LangRewritingContext context; + + private final Expression groupVar; + + private final Map<Expression, Identifier> fieldVars; + + private final Collection<VariableExpr> outerVars; + + Sql92AggregateFunctionVisitor(LangRewritingContext context, VariableExpr groupVar, + Map<Expression, Identifier> fieldVars, Collection<VariableExpr> outerVars) { + this.context = context; + this.groupVar = groupVar; + this.fieldVars = fieldVars; + this.outerVars = outerVars; + } + + @Override + public Expression visit(CallExpr callExpr, ILangExpression arg) throws CompilationException { + List<Expression> newExprList = new ArrayList<>(); + FunctionSignature signature = callExpr.getFunctionSignature(); + boolean aggregate = FunctionMapUtil.isSql92AggregateFunction(signature); + boolean rewritten = false; + for (Expression expr : callExpr.getExprList()) { + Expression newExpr = + aggregate ? wrapAggregationArgument(expr, groupVar, fieldVars, outerVars, context) : expr; + rewritten |= newExpr != expr; + newExprList.add(newExpr.accept(this, arg)); + } + if (rewritten) { + // Rewrites the SQL-92 function name to core functions, + // e.g., SUM --> array_sum + callExpr.setFunctionSignature(FunctionMapUtil.sql92ToCoreAggregateFunction(signature)); + } + callExpr.setExprList(newExprList); + return callExpr; + } + + static Expression wrapAggregationArgument(Expression expr, Expression groupVar, + Map<Expression, Identifier> fieldVars, Collection<VariableExpr> outerVars, LangRewritingContext context) + throws CompilationException { + SourceLocation sourceLoc = expr.getSourceLocation(); + Set<VariableExpr> freeVars = SqlppRewriteUtil.getFreeVariable(expr); + + VariableExpr fromBindingVar = new VariableExpr(context.newVariable()); + fromBindingVar.setSourceLocation(sourceLoc); + FromTerm fromTerm = new FromTerm(groupVar, fromBindingVar, null, null); + fromTerm.setSourceLocation(sourceLoc); + FromClause fromClause = new FromClause(Collections.singletonList(fromTerm)); + fromClause.setSourceLocation(sourceLoc); + + // Maps field variable expressions to field accesses. + Map<Expression, Expression> varExprMap = new HashMap<>(); + for (VariableExpr usedVar : freeVars) { + // Reference to a field in the group variable. + if (fieldVars.containsKey(usedVar)) { + // Rewrites to a reference to a field in the group variable. + FieldAccessor fa = + new FieldAccessor(fromBindingVar, new VarIdentifier(fieldVars.get(usedVar).getValue())); + fa.setSourceLocation(usedVar.getSourceLocation()); + varExprMap.put(usedVar, fa); + } else if (outerVars.contains(usedVar)) { + // Do nothing + } else { + // Rewrites to a reference to a single field in the group variable. + Identifier ident = findField(fieldVars, usedVar, context); + FieldAccessor faInner = new FieldAccessor(fromBindingVar, ident); + faInner.setSourceLocation(usedVar.getSourceLocation()); + FieldAccessor faOuter = + new FieldAccessor(faInner, SqlppVariableUtil.toUserDefinedVariableName(usedVar.getVar())); + faOuter.setSourceLocation(usedVar.getSourceLocation()); + varExprMap.put(usedVar, faOuter); + } + } + + // Select clause. + SelectElement selectElement = + new SelectElement(SqlppRewriteUtil.substituteExpression(expr, varExprMap, context)); + selectElement.setSourceLocation(sourceLoc); + SelectClause selectClause = new SelectClause(selectElement, null, false); + selectClause.setSourceLocation(sourceLoc); + + // Construct the select expression. + SelectBlock selectBlock = new SelectBlock(selectClause, fromClause, null, null, null, null, null); + selectBlock.setSourceLocation(sourceLoc); + SelectSetOperation selectSetOperation = new SelectSetOperation(new SetOperationInput(selectBlock, null), null); + selectSetOperation.setSourceLocation(sourceLoc); + SelectExpression selectExpr = new SelectExpression(null, selectSetOperation, null, null, true); + selectExpr.setSourceLocation(sourceLoc); + return selectExpr; + } + + private static Identifier findField(Map<Expression, Identifier> fieldVars, VariableExpr usedVar, + LangRewritingContext context) throws CompilationException { + Identifier ident = null; + for (Map.Entry<Expression, Identifier> me : fieldVars.entrySet()) { + Expression fieldVarExpr = me.getKey(); + if (fieldVarExpr.getKind() == Expression.Kind.VARIABLE_EXPRESSION + && context.isExcludedForFieldAccessVar(((VariableExpr) fieldVarExpr).getVar())) { + continue; + } + if (ident != null) { + throw new CompilationException(ErrorCode.AMBIGUOUS_IDENTIFIER, usedVar.getSourceLocation(), + SqlppVariableUtil.toUserDefinedVariableName(usedVar.getVar().getValue()).getValue()); + } + ident = me.getValue(); + } + if (ident == null) { + throw new CompilationException(ErrorCode.COMPILATION_ERROR, usedVar.getSourceLocation()); + } + return ident; + } +} http://git-wip-us.apache.org/repos/asf/asterixdb/blob/f2c18aa9/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/SqlppBuiltinFunctionRewriteVisitor.java ---------------------------------------------------------------------- diff --git a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/SqlppBuiltinFunctionRewriteVisitor.java b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/SqlppBuiltinFunctionRewriteVisitor.java index abfa14e..82284f3 100644 --- a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/SqlppBuiltinFunctionRewriteVisitor.java +++ b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/SqlppBuiltinFunctionRewriteVisitor.java @@ -31,6 +31,7 @@ import org.apache.asterix.lang.common.expression.OperatorExpr; import org.apache.asterix.lang.common.literal.TrueLiteral; import org.apache.asterix.lang.common.struct.OperatorType; import org.apache.asterix.lang.sqlpp.expression.CaseExpression; +import org.apache.asterix.lang.sqlpp.expression.WindowExpression; import org.apache.asterix.lang.sqlpp.util.FunctionMapUtil; import org.apache.asterix.lang.sqlpp.util.SqlppRewriteUtil; import org.apache.asterix.lang.sqlpp.visitor.base.AbstractSqlppSimpleExpressionVisitor; @@ -41,15 +42,16 @@ public class SqlppBuiltinFunctionRewriteVisitor extends AbstractSqlppSimpleExpre @Override public Expression visit(CallExpr callExpr, ILangExpression arg) throws CompilationException { //TODO(buyingyi): rewrite SQL temporal functions - FunctionSignature functionSignature = callExpr.getFunctionSignature(); - callExpr.setFunctionSignature(FunctionMapUtil.normalizeBuiltinFunctionSignature(functionSignature, true, - callExpr.getSourceLocation())); - List<Expression> newExprList = new ArrayList<>(); - for (Expression expr : callExpr.getExprList()) { - newExprList.add(expr.accept(this, arg)); - } - callExpr.setExprList(newExprList); - return callExpr; + callExpr.setFunctionSignature(FunctionMapUtil.normalizeBuiltinFunctionSignature(callExpr.getFunctionSignature(), + true, callExpr.getSourceLocation())); + return super.visit(callExpr, arg); + } + + @Override + public Expression visit(WindowExpression winExpr, ILangExpression arg) throws CompilationException { + winExpr.setFunctionSignature(FunctionMapUtil.normalizeBuiltinFunctionSignature(winExpr.getFunctionSignature(), + true, winExpr.getSourceLocation())); + return super.visit(winExpr, arg); } @Override http://git-wip-us.apache.org/repos/asf/asterixdb/blob/f2c18aa9/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/SqlppGroupByAggregationSugarVisitor.java ---------------------------------------------------------------------- diff --git a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/SqlppGroupByAggregationSugarVisitor.java b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/SqlppGroupByAggregationSugarVisitor.java index a73d44e..1c55f99 100644 --- a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/SqlppGroupByAggregationSugarVisitor.java +++ b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/SqlppGroupByAggregationSugarVisitor.java @@ -19,42 +19,28 @@ package org.apache.asterix.lang.sqlpp.rewrites.visitor; import org.apache.asterix.common.exceptions.CompilationException; -import org.apache.asterix.common.exceptions.ErrorCode; -import org.apache.asterix.common.functions.FunctionSignature; import org.apache.asterix.lang.common.base.Expression; import org.apache.asterix.lang.common.base.ILangExpression; import org.apache.asterix.lang.common.clause.GroupbyClause; import org.apache.asterix.lang.common.clause.LetClause; import org.apache.asterix.lang.common.clause.LimitClause; import org.apache.asterix.lang.common.clause.OrderbyClause; -import org.apache.asterix.lang.common.expression.CallExpr; -import org.apache.asterix.lang.common.expression.FieldAccessor; import org.apache.asterix.lang.common.expression.GbyVariableExpressionPair; import org.apache.asterix.lang.common.expression.VariableExpr; import org.apache.asterix.lang.common.rewrites.LangRewritingContext; import org.apache.asterix.lang.common.struct.Identifier; -import org.apache.asterix.lang.common.struct.VarIdentifier; import org.apache.asterix.lang.sqlpp.clause.FromClause; -import org.apache.asterix.lang.sqlpp.clause.FromTerm; import org.apache.asterix.lang.sqlpp.clause.HavingClause; import org.apache.asterix.lang.sqlpp.clause.SelectBlock; import org.apache.asterix.lang.sqlpp.clause.SelectClause; -import org.apache.asterix.lang.sqlpp.clause.SelectElement; -import org.apache.asterix.lang.sqlpp.clause.SelectSetOperation; import org.apache.asterix.lang.sqlpp.expression.SelectExpression; -import org.apache.asterix.lang.sqlpp.struct.SetOperationInput; -import org.apache.asterix.lang.sqlpp.util.FunctionMapUtil; import org.apache.asterix.lang.sqlpp.util.SqlppRewriteUtil; import org.apache.asterix.lang.sqlpp.util.SqlppVariableUtil; import org.apache.asterix.lang.sqlpp.visitor.base.AbstractSqlppExpressionScopingVisitor; -import org.apache.asterix.lang.sqlpp.visitor.base.AbstractSqlppSimpleExpressionVisitor; -import org.apache.hyracks.algebricks.common.utils.Pair; -import org.apache.hyracks.api.exceptions.SourceLocation; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; -import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; @@ -198,11 +184,14 @@ public class SqlppGroupByAggregationSugarVisitor extends AbstractSqlppExpression // is not able to optimize the latter case. The following query is such an example: // asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/dapd/q2-11 List<GbyVariableExpressionPair> decorList = new ArrayList<>(); + if (groupbyClause.hasDecorList()) { + decorList.addAll(groupbyClause.getDecorPairList()); + } for (VariableExpr var : decorVars) { decorList.add(new GbyVariableExpressionPair((VariableExpr) SqlppRewriteUtil.deepCopy(var), (Expression) SqlppRewriteUtil.deepCopy(var))); } - groupbyClause.getDecorPairList().addAll(decorList); + groupbyClause.setDecorPairList(decorList); } } else { selectBlock.getSelectClause().accept(this, arg); @@ -211,110 +200,15 @@ public class SqlppGroupByAggregationSugarVisitor extends AbstractSqlppExpression } private Map<Expression, Identifier> getGroupFieldVariables(GroupbyClause groupbyClause) { - Map<Expression, Identifier> fieldVars = new HashMap<>(); - for (Pair<Expression, Identifier> groupField : groupbyClause.getGroupFieldList()) { - fieldVars.put(groupField.first, groupField.second); - } - return fieldVars; + return groupbyClause.hasGroupFieldList() + ? SqlppVariableUtil.createFieldVariableMap(groupbyClause.getGroupFieldList()) : Collections.emptyMap(); } // Applying sugar rewriting for group-by. private void rewriteExpressionUsingGroupVariable(VariableExpr groupVar, Map<Expression, Identifier> fieldVars, ILangExpression expr, Set<VariableExpr> outerScopeVariables) throws CompilationException { Sql92AggregateFunctionVisitor visitor = - new Sql92AggregateFunctionVisitor(groupVar, fieldVars, outerScopeVariables); + new Sql92AggregateFunctionVisitor(context, groupVar, fieldVars, outerScopeVariables); expr.accept(visitor, null); } - - private final class Sql92AggregateFunctionVisitor extends AbstractSqlppSimpleExpressionVisitor { - - private final Expression groupVar; - - private final Map<Expression, Identifier> fieldVars; - - private final Collection<VariableExpr> outerVars; - - private Sql92AggregateFunctionVisitor(Expression groupVar, Map<Expression, Identifier> fieldVars, - Collection<VariableExpr> outerVars) { - this.groupVar = groupVar; - this.fieldVars = fieldVars; - this.outerVars = outerVars; - } - - @Override - public Expression visit(CallExpr callExpr, ILangExpression arg) throws CompilationException { - List<Expression> newExprList = new ArrayList<>(); - FunctionSignature signature = callExpr.getFunctionSignature(); - boolean aggregate = FunctionMapUtil.isSql92AggregateFunction(signature); - boolean rewritten = false; - for (Expression expr : callExpr.getExprList()) { - Expression newExpr = aggregate ? wrapAggregationArgument(expr) : expr; - rewritten |= newExpr != expr; - newExprList.add(newExpr.accept(this, arg)); - } - if (rewritten) { - // Rewrites the SQL-92 function name to core functions, - // e.g., SUM --> array_sum - callExpr.setFunctionSignature(FunctionMapUtil.sql92ToCoreAggregateFunction(signature)); - } - callExpr.setExprList(newExprList); - return callExpr; - } - - private Expression wrapAggregationArgument(Expression argExpr) throws CompilationException { - SourceLocation sourceLoc = argExpr.getSourceLocation(); - Expression expr = argExpr; - Set<VariableExpr> freeVars = SqlppRewriteUtil.getFreeVariable(expr); - - VariableExpr fromBindingVar = new VariableExpr(context.newVariable()); - fromBindingVar.setSourceLocation(sourceLoc); - FromTerm fromTerm = new FromTerm(groupVar, fromBindingVar, null, null); - fromTerm.setSourceLocation(sourceLoc); - FromClause fromClause = new FromClause(Collections.singletonList(fromTerm)); - fromClause.setSourceLocation(sourceLoc); - - // Maps field variable expressions to field accesses. - Map<Expression, Expression> varExprMap = new HashMap<>(); - for (VariableExpr usedVar : freeVars) { - // Reference to a field in the group variable. - if (fieldVars.containsKey(usedVar)) { - // Rewrites to a reference to a field in the group variable. - FieldAccessor fa = - new FieldAccessor(fromBindingVar, new VarIdentifier(fieldVars.get(usedVar).getValue())); - fa.setSourceLocation(usedVar.getSourceLocation()); - varExprMap.put(usedVar, fa); - } else if (outerVars.contains(usedVar)) { - // Do nothing - } else if (fieldVars.size() == 1) { - // Rewrites to a reference to a single field in the group variable. - FieldAccessor faInner = new FieldAccessor(fromBindingVar, fieldVars.values().iterator().next()); - faInner.setSourceLocation(usedVar.getSourceLocation()); - FieldAccessor faOuter = - new FieldAccessor(faInner, SqlppVariableUtil.toUserDefinedVariableName(usedVar.getVar())); - faOuter.setSourceLocation(usedVar.getSourceLocation()); - varExprMap.put(usedVar, faOuter); - } else { - throw new CompilationException(ErrorCode.AMBIGUOUS_IDENTIFIER, usedVar.getSourceLocation(), - SqlppVariableUtil.toUserDefinedVariableName(usedVar.getVar().getValue()).getValue()); - } - } - - // Select clause. - SelectElement selectElement = - new SelectElement(SqlppRewriteUtil.substituteExpression(expr, varExprMap, context)); - selectElement.setSourceLocation(sourceLoc); - SelectClause selectClause = new SelectClause(selectElement, null, false); - selectClause.setSourceLocation(sourceLoc); - - // Construct the select expression. - SelectBlock selectBlock = new SelectBlock(selectClause, fromClause, null, null, null, null, null); - selectBlock.setSourceLocation(sourceLoc); - SelectSetOperation selectSetOperation = - new SelectSetOperation(new SetOperationInput(selectBlock, null), null); - selectSetOperation.setSourceLocation(sourceLoc); - SelectExpression selectExpr = new SelectExpression(null, selectSetOperation, null, null, true); - selectExpr.setSourceLocation(sourceLoc); - return selectExpr; - } - } } http://git-wip-us.apache.org/repos/asf/asterixdb/blob/f2c18aa9/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/SqlppGroupByVisitor.java ---------------------------------------------------------------------- diff --git a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/SqlppGroupByVisitor.java b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/SqlppGroupByVisitor.java index faca85e..84aee71 100644 --- a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/SqlppGroupByVisitor.java +++ b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/SqlppGroupByVisitor.java @@ -34,7 +34,6 @@ import org.apache.asterix.lang.sqlpp.visitor.base.AbstractSqlppSimpleExpressionV import org.apache.hyracks.algebricks.common.utils.Pair; import java.util.ArrayList; -import java.util.Collection; import java.util.HashMap; import java.util.List; @@ -123,19 +122,14 @@ public class SqlppGroupByVisitor extends AbstractSqlppSimpleExpressionVisitor { private List<Pair<Expression, Identifier>> createGroupFieldList(SelectBlock selectBlock) { List<Pair<Expression, Identifier>> groupFieldList = new ArrayList<>(); - addToGroupFieldList(groupFieldList, SqlppVariableUtil.getBindingVariables(selectBlock.getFromClause())); - addToGroupFieldList(groupFieldList, SqlppVariableUtil.getBindingVariables(selectBlock.getLetList())); + addToFieldList(groupFieldList, SqlppVariableUtil.getBindingVariables(selectBlock.getFromClause())); + addToFieldList(groupFieldList, SqlppVariableUtil.getBindingVariables(selectBlock.getLetList())); return groupFieldList; } - private void addToGroupFieldList(List<Pair<Expression, Identifier>> groupFieldList, - Collection<VariableExpr> fromBindingVars) { - for (VariableExpr varExpr : fromBindingVars) { - VariableExpr newVarExpr = new VariableExpr(varExpr.getVar()); - newVarExpr.setSourceLocation(varExpr.getSourceLocation()); - Pair<Expression, Identifier> varIdPair = - new Pair<>(newVarExpr, SqlppVariableUtil.toUserDefinedVariableName(varExpr.getVar())); - groupFieldList.add(varIdPair); + private void addToFieldList(List<Pair<Expression, Identifier>> outFieldList, List<VariableExpr> varList) { + for (VariableExpr varExpr : varList) { + SqlppVariableUtil.addToFieldVariableList(varExpr, outFieldList); } } } http://git-wip-us.apache.org/repos/asf/asterixdb/blob/f2c18aa9/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/SqlppInlineUdfsVisitor.java ---------------------------------------------------------------------- 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 0ffb590..1fd4ff7 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 @@ -28,6 +28,7 @@ import org.apache.asterix.lang.common.base.IRewriterFactory; import org.apache.asterix.lang.common.clause.LetClause; import org.apache.asterix.lang.common.rewrites.LangRewritingContext; import org.apache.asterix.lang.common.statement.FunctionDecl; +import org.apache.asterix.lang.common.struct.Identifier; import org.apache.asterix.lang.common.visitor.AbstractInlineUdfsVisitor; import org.apache.asterix.lang.sqlpp.clause.AbstractBinaryCorrelateClause; import org.apache.asterix.lang.sqlpp.clause.FromClause; @@ -247,16 +248,35 @@ public class SqlppInlineUdfsVisitor extends AbstractInlineUdfsVisitor @Override public Boolean visit(WindowExpression winExpr, List<FunctionDecl> funcs) throws CompilationException { - Pair<Boolean, Expression> result = inlineUdfsInExpr(winExpr.getExpr(), funcs); - winExpr.setExpr(result.second); - boolean inlined = result.first; + boolean inlined = false; if (winExpr.hasPartitionList()) { Pair<Boolean, List<Expression>> inlinedList = inlineUdfsInExprList(winExpr.getPartitionList(), funcs); winExpr.setPartitionList(inlinedList.second); + inlined = inlinedList.first; + } + if (winExpr.hasOrderByList()) { + Pair<Boolean, List<Expression>> inlinedList = inlineUdfsInExprList(winExpr.getOrderbyList(), funcs); + winExpr.setOrderbyList(inlinedList.second); + inlined |= inlinedList.first; + } + if (winExpr.hasFrameStartExpr()) { + Pair<Boolean, Expression> inlinedExpr = inlineUdfsInExpr(winExpr.getFrameStartExpr(), funcs); + winExpr.setFrameStartExpr(inlinedExpr.second); + inlined |= inlinedExpr.first; + } + if (winExpr.hasFrameEndExpr()) { + Pair<Boolean, Expression> inlinedExpr = inlineUdfsInExpr(winExpr.getFrameEndExpr(), funcs); + winExpr.setFrameEndExpr(inlinedExpr.second); + inlined |= inlinedExpr.first; + } + if (winExpr.hasWindowFieldList()) { + Pair<Boolean, List<Pair<Expression, Identifier>>> inlinedList = + inlineUdfsInFieldList(winExpr.getWindowFieldList(), funcs); + winExpr.setWindowFieldList(inlinedList.second); inlined |= inlinedList.first; } - Pair<Boolean, List<Expression>> inlinedList = inlineUdfsInExprList(winExpr.getOrderbyList(), funcs); - winExpr.setOrderbyList(inlinedList.second); + Pair<Boolean, List<Expression>> inlinedList = inlineUdfsInExprList(winExpr.getExprList(), funcs); + winExpr.setExprList(inlinedList.second); inlined |= inlinedList.first; return inlined; } http://git-wip-us.apache.org/repos/asf/asterixdb/blob/f2c18aa9/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/SqlppWindowAggregationSugarVisitor.java ---------------------------------------------------------------------- diff --git a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/SqlppWindowAggregationSugarVisitor.java b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/SqlppWindowAggregationSugarVisitor.java new file mode 100644 index 0000000..fa40d78 --- /dev/null +++ b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/SqlppWindowAggregationSugarVisitor.java @@ -0,0 +1,138 @@ +/* + * 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.sqlpp.rewrites.visitor; + +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.Deque; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.apache.asterix.common.exceptions.CompilationException; +import org.apache.asterix.common.functions.FunctionSignature; +import org.apache.asterix.lang.common.base.Expression; +import org.apache.asterix.lang.common.base.ILangExpression; +import org.apache.asterix.lang.common.expression.VariableExpr; +import org.apache.asterix.lang.common.rewrites.LangRewritingContext; +import org.apache.asterix.lang.common.struct.Identifier; +import org.apache.asterix.lang.sqlpp.clause.SelectBlock; +import org.apache.asterix.lang.sqlpp.expression.WindowExpression; +import org.apache.asterix.lang.sqlpp.util.FunctionMapUtil; +import org.apache.asterix.lang.sqlpp.util.SqlppVariableUtil; +import org.apache.asterix.lang.sqlpp.visitor.base.AbstractSqlppExpressionScopingVisitor; +import org.apache.asterix.om.functions.BuiltinFunctions; +import org.apache.hyracks.algebricks.common.utils.Pair; +import org.apache.hyracks.algebricks.core.algebra.functions.FunctionIdentifier; + +/** + * A pre-processor that adds a window field list into the AST: + * + * <pre> + * FROM ... AS e, ... AS i + * SELECT fn() OVER (...) + * -> + * FROM ... AS e, ... AS i + * SELECT fn() AS w(e AS e, i AS i) OVER (...) + * </pre> + * + * Also rewrites SQL-92 aggregate functions inside window expressions into SQL++ core aggregate functions + * using the same approach as {@link SqlppGroupByAggregationSugarVisitor} + * <br/> + * Must be executed after {@link VariableCheckAndRewriteVisitor} + */ +public class SqlppWindowAggregationSugarVisitor extends AbstractSqlppExpressionScopingVisitor { + + private final Deque<SelectBlock> stack = new ArrayDeque<>(); + + public SqlppWindowAggregationSugarVisitor(LangRewritingContext context) { + super(context); + } + + @Override + public Expression visit(SelectBlock selectBlock, ILangExpression arg) throws CompilationException { + stack.push(selectBlock); + Expression expr = super.visit(selectBlock, arg); + stack.pop(); + return expr; + } + + @Override + public Expression visit(WindowExpression winExpr, ILangExpression arg) throws CompilationException { + if (!winExpr.hasWindowFieldList()) { + SelectBlock selectBlock = stack.peek(); + List<Pair<Expression, Identifier>> winFieldList = createWindowFieldList(selectBlock); + winExpr.setWindowFieldList(winFieldList); + } + + FunctionSignature signature = winExpr.getFunctionSignature(); + FunctionIdentifier winfi = FunctionMapUtil.getInternalWindowFunction(signature); + if (winfi != null) { + winExpr.setFunctionSignature(new FunctionSignature(winfi)); + if (BuiltinFunctions.windowFunctionWithListArg(winfi)) { + wrapAggregationArguments(winExpr, 1); + } + } else if (FunctionMapUtil.isSql92AggregateFunction(signature)) { + winExpr.setFunctionSignature(FunctionMapUtil.sql92ToCoreAggregateFunction(signature)); + wrapAggregationArguments(winExpr, winExpr.getExprList().size()); + } + + return super.visit(winExpr, arg); + } + + private void wrapAggregationArguments(WindowExpression winExpr, int limit) throws CompilationException { + Set<VariableExpr> liveVars = scopeChecker.getCurrentScope().getLiveVariables(); + + VariableExpr winVar = winExpr.getWindowVar(); + List<Pair<Expression, Identifier>> winFieldList = winExpr.getWindowFieldList(); + Map<Expression, Identifier> fieldMap = SqlppVariableUtil.createFieldVariableMap(winFieldList); + + List<Expression> exprList = winExpr.getExprList(); + int n = exprList.size(); + List<Expression> newExprList = new ArrayList<>(n); + for (int i = 0; i < n; i++) { + Expression expr = exprList.get(i); + Expression newExpr = i < limit + ? Sql92AggregateFunctionVisitor.wrapAggregationArgument(expr, winVar, fieldMap, liveVars, context) + : expr; + newExprList.add(newExpr); + } + winExpr.setExprList(newExprList); + } + + private List<Pair<Expression, Identifier>> createWindowFieldList(SelectBlock selectBlock) { + List<Pair<Expression, Identifier>> fieldList = new ArrayList<>(); + if (selectBlock != null) { + addToFieldList(fieldList, SqlppVariableUtil.getBindingVariables(selectBlock.getFromClause())); + addToFieldList(fieldList, SqlppVariableUtil.getBindingVariables(selectBlock.getLetList())); + addToFieldList(fieldList, SqlppVariableUtil.getBindingVariables(selectBlock.getGroupbyClause())); + addToFieldList(fieldList, SqlppVariableUtil.getBindingVariables(selectBlock.getLetListAfterGroupby())); + } + return fieldList; + } + + private void addToFieldList(List<Pair<Expression, Identifier>> outFieldList, List<VariableExpr> varList) { + for (VariableExpr varExpr : varList) { + if (scopeChecker.lookupSymbol(varExpr.getVar().getValue()) != null) { + SqlppVariableUtil.addToFieldVariableList(varExpr, outFieldList); + } + } + } +} http://git-wip-us.apache.org/repos/asf/asterixdb/blob/f2c18aa9/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/SqlppWindowRewriteVisitor.java ---------------------------------------------------------------------- diff --git a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/SqlppWindowRewriteVisitor.java b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/SqlppWindowRewriteVisitor.java new file mode 100644 index 0000000..cd0e151 --- /dev/null +++ b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/SqlppWindowRewriteVisitor.java @@ -0,0 +1,97 @@ +/* + * 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.sqlpp.rewrites.visitor; + +import java.util.List; + +import org.apache.asterix.common.exceptions.CompilationException; +import org.apache.asterix.common.exceptions.ErrorCode; +import org.apache.asterix.common.functions.FunctionSignature; +import org.apache.asterix.lang.common.base.Expression; +import org.apache.asterix.lang.common.base.ILangExpression; +import org.apache.asterix.lang.common.expression.VariableExpr; +import org.apache.asterix.lang.common.rewrites.LangRewritingContext; +import org.apache.asterix.lang.common.struct.VarIdentifier; +import org.apache.asterix.lang.sqlpp.clause.FromClause; +import org.apache.asterix.lang.sqlpp.expression.WindowExpression; +import org.apache.asterix.lang.sqlpp.util.FunctionMapUtil; +import org.apache.asterix.om.functions.BuiltinFunctions; +import org.apache.hyracks.algebricks.common.utils.Pair; +import org.apache.hyracks.algebricks.core.algebra.functions.FunctionIdentifier; + +/** + * A pre-processor that transforms window expressions as follows: + * <ul> + * <li>adds window frame variable</li> + * <li>extracts list arguments of window functions into separate LET clauses</li> + * </ul> + * + * Must be executed before {@link VariableCheckAndRewriteVisitor} + */ +public final class SqlppWindowRewriteVisitor extends AbstractSqlppExpressionExtractionVisitor { + + public SqlppWindowRewriteVisitor(LangRewritingContext context) { + super(context); + } + + @Override + public Expression visit(WindowExpression winExpr, ILangExpression arg) throws CompilationException { + super.visit(winExpr, arg); + + if (!winExpr.hasWindowVar()) { + VariableExpr winVar = new VariableExpr(context.newVariable()); + winVar.setSourceLocation(winExpr.getSourceLocation()); + winExpr.setWindowVar(winVar); + } + + FunctionSignature signature = winExpr.getFunctionSignature(); + FunctionIdentifier winfi = FunctionMapUtil.getInternalWindowFunction(signature); + if (winfi != null) { + if (BuiltinFunctions.windowFunctionWithListArg(winfi)) { + List<Expression> newExprList = + extractExpressions(winExpr.getExprList(), 1, winExpr.getSourceLocation()); + winExpr.setExprList(newExprList); + } + } else if (FunctionMapUtil.isSql92AggregateFunction(signature)) { + List<Expression> newExprList = extractExpressions(winExpr.getExprList(), winExpr.getExprList().size(), + winExpr.getSourceLocation()); + winExpr.setExprList(newExprList); + } + + return winExpr; + } + + @Override + protected boolean isExtractableExpression(Expression expr) { + switch (expr.getKind()) { + case LITERAL_EXPRESSION: + case VARIABLE_EXPRESSION: + return false; + default: + return true; + } + } + + @Override + void handleUnsupportedClause(FromClause clause, List<Pair<Expression, VarIdentifier>> extractionList) + throws CompilationException { + throw new CompilationException(ErrorCode.COMPILATION_UNEXPECTED_WINDOW_EXPRESSION, clause.getSourceLocation()); + } +} http://git-wip-us.apache.org/repos/asf/asterixdb/blob/f2c18aa9/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/VariableCheckAndRewriteVisitor.java ---------------------------------------------------------------------- diff --git a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/VariableCheckAndRewriteVisitor.java b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/VariableCheckAndRewriteVisitor.java index 8bac4ad..b48e024 100644 --- a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/VariableCheckAndRewriteVisitor.java +++ b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/visitor/VariableCheckAndRewriteVisitor.java @@ -20,6 +20,7 @@ package org.apache.asterix.lang.sqlpp.rewrites.visitor; import java.util.ArrayList; import java.util.Collection; +import java.util.Iterator; import java.util.List; import java.util.Set; @@ -37,6 +38,7 @@ import org.apache.asterix.lang.common.literal.StringLiteral; import org.apache.asterix.lang.common.rewrites.LangRewritingContext; import org.apache.asterix.lang.common.struct.Identifier; import org.apache.asterix.lang.common.struct.VarIdentifier; +import org.apache.asterix.lang.sqlpp.expression.WindowExpression; import org.apache.asterix.lang.sqlpp.util.FunctionMapUtil; import org.apache.asterix.lang.sqlpp.util.SqlppVariableUtil; import org.apache.asterix.lang.sqlpp.visitor.CheckDatasetOnlyResolutionVisitor; @@ -45,6 +47,7 @@ import org.apache.asterix.metadata.declared.MetadataProvider; import org.apache.asterix.om.functions.BuiltinFunctions; import org.apache.commons.lang3.StringUtils; import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException; +import org.apache.hyracks.algebricks.core.algebra.functions.FunctionIdentifier; import org.apache.hyracks.api.exceptions.SourceLocation; public class VariableCheckAndRewriteVisitor extends AbstractSqlppExpressionScopingVisitor { @@ -201,7 +204,6 @@ public class VariableCheckAndRewriteVisitor extends AbstractSqlppExpressionScopi return path.length == 2 && metadataProvider.findDataset(path[0], path[1]) != null; } - @Override public Expression visit(CallExpr callExpr, ILangExpression arg) throws CompilationException { // skip variables inside SQL-92 aggregates (they will be resolved by SqlppGroupByAggregationSugarVisitor) if (FunctionMapUtil.isSql92AggregateFunction(callExpr.getFunctionSignature())) { @@ -209,4 +211,29 @@ public class VariableCheckAndRewriteVisitor extends AbstractSqlppExpressionScopi } return super.visit(callExpr, arg); } + + @Override + public Expression visit(WindowExpression winExpr, ILangExpression arg) throws CompilationException { + // skip variables inside list arguments of window functions (will be resolved by SqlppWindowExpressionVisitor) + FunctionSignature fs = winExpr.getFunctionSignature(); + FunctionIdentifier winfi = FunctionMapUtil.getInternalWindowFunction(fs); + if (winfi != null) { + if (BuiltinFunctions.windowFunctionWithListArg(winfi)) { + visitWindowExpressionExcludingExprList(winExpr, arg); + List<Expression> exprList = winExpr.getExprList(); + List<Expression> newExprList = new ArrayList<>(exprList.size()); + Iterator<Expression> i = exprList.iterator(); + newExprList.add(i.next()); // don't visit the list arg + while (i.hasNext()) { + newExprList.add(visit(i.next(), arg)); + } + winExpr.setExprList(newExprList); + return winExpr; + } + } else if (FunctionMapUtil.isSql92AggregateFunction(fs)) { + visitWindowExpressionExcludingExprList(winExpr, arg); + return winExpr; + } + return super.visit(winExpr, arg); + } } http://git-wip-us.apache.org/repos/asf/asterixdb/blob/f2c18aa9/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/util/FunctionMapUtil.java ---------------------------------------------------------------------- diff --git a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/util/FunctionMapUtil.java b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/util/FunctionMapUtil.java index 7773072..a6fa730 100644 --- a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/util/FunctionMapUtil.java +++ b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/util/FunctionMapUtil.java @@ -63,7 +63,7 @@ public class FunctionMapUtil { * @return true if the function signature is a SQL-92 core aggregate, * false otherwise. */ - public static boolean isSql92AggregateFunction(FunctionSignature signature) throws CompilationException { + public static boolean isSql92AggregateFunction(FunctionSignature signature) { IFunctionInfo finfo = FunctionUtil.getFunctionInfo(new FunctionIdentifier(FunctionConstants.ASTERIX_NS, signature.getName().toLowerCase(), signature.getArity())); if (finfo == null) { @@ -78,9 +78,8 @@ public class FunctionMapUtil { * @param fs, * the SQL-92 aggregate function signature. * @return the SQL++ aggregate function signature. - * @throws CompilationException */ - public static FunctionSignature sql92ToCoreAggregateFunction(FunctionSignature fs) throws CompilationException { + public static FunctionSignature sql92ToCoreAggregateFunction(FunctionSignature fs) { if (!isSql92AggregateFunction(fs)) { return fs; } @@ -110,11 +109,15 @@ public class FunctionMapUtil { if (finfo != null && BuiltinFunctions.getAggregateFunction(finfo.getFunctionIdentifier()) != null) { return new FunctionSignature(FunctionConstants.ASTERIX_NS, internalName, fs.getArity()); } - } else if (checkSql92Aggregate && isSql92AggregateFunction(fs)) { - throw new CompilationException(ErrorCode.COMPILATION_ERROR, sourceLoc, - fs.getName() + " is a SQL-92 aggregate function. The SQL++ core aggregate function " - + CORE_SQL_AGGREGATE_PREFIX + fs.getName().toLowerCase() - + " could potentially express the intent."); + } else if (checkSql92Aggregate) { + if (isSql92AggregateFunction(fs)) { + throw new CompilationException(ErrorCode.COMPILATION_ERROR, sourceLoc, + fs.getName() + " is a SQL-92 aggregate function. The SQL++ core aggregate function " + + CORE_SQL_AGGREGATE_PREFIX + fs.getName().toLowerCase() + + " could potentially express the intent."); + } else if (getInternalWindowFunction(fs) != null) { + throw new CompilationException(ErrorCode.COMPILATION_UNEXPECTED_WINDOW_EXPRESSION, sourceLoc); + } } String mappedName = CommonFunctionMapUtil.normalizeBuiltinFunctionSignature(fs).getName(); return new FunctionSignature(fs.getNamespace(), mappedName, fs.getArity()); @@ -160,4 +163,16 @@ public class FunctionMapUtil { return null; } } + + /** + * Returns an internal implementation function for a public window function, + * or {@code null} if given function is not a public window function + * @param signature function signature + * @return said value + */ + public static FunctionIdentifier getInternalWindowFunction(FunctionSignature signature) { + IFunctionInfo finfo = FunctionUtil.getFunctionInfo(new FunctionIdentifier(FunctionConstants.ASTERIX_NS, + signature.getName().toLowerCase(), signature.getArity())); + return finfo != null ? BuiltinFunctions.getWindowFunction(finfo.getFunctionIdentifier()) : null; + } } http://git-wip-us.apache.org/repos/asf/asterixdb/blob/f2c18aa9/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/util/SqlppVariableUtil.java ---------------------------------------------------------------------- diff --git a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/util/SqlppVariableUtil.java b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/util/SqlppVariableUtil.java index 14dfaeb..8fabf13 100644 --- a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/util/SqlppVariableUtil.java +++ b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/util/SqlppVariableUtil.java @@ -21,20 +21,27 @@ package org.apache.asterix.lang.sqlpp.util; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Map; +import java.util.Set; import org.apache.asterix.common.exceptions.CompilationException; +import org.apache.asterix.lang.common.base.Expression; import org.apache.asterix.lang.common.base.ILangExpression; import org.apache.asterix.lang.common.clause.GroupbyClause; import org.apache.asterix.lang.common.clause.LetClause; import org.apache.asterix.lang.common.expression.GbyVariableExpressionPair; import org.apache.asterix.lang.common.expression.VariableExpr; +import org.apache.asterix.lang.common.struct.Identifier; import org.apache.asterix.lang.common.struct.VarIdentifier; import org.apache.asterix.lang.sqlpp.clause.AbstractBinaryCorrelateClause; import org.apache.asterix.lang.sqlpp.clause.FromClause; import org.apache.asterix.lang.sqlpp.clause.FromTerm; +import org.apache.asterix.lang.sqlpp.clause.SelectBlock; import org.apache.asterix.lang.sqlpp.visitor.FreeVariableVisitor; +import org.apache.hyracks.algebricks.common.utils.Pair; public class SqlppVariableUtil { @@ -96,14 +103,14 @@ public class SqlppVariableUtil { return isExternalVariableIdentifier(varExpr.getVar()); } - public static Collection<VariableExpr> getFreeVariables(ILangExpression langExpr) throws CompilationException { - Collection<VariableExpr> freeVars = new HashSet<>(); + public static Set<VariableExpr> getFreeVariables(ILangExpression langExpr) throws CompilationException { + Set<VariableExpr> freeVars = new HashSet<>(); FreeVariableVisitor visitor = new FreeVariableVisitor(); langExpr.accept(visitor, freeVars); return freeVars; } - public static Collection<VariableExpr> getBindingVariables(FromClause fromClause) { + public static List<VariableExpr> getBindingVariables(FromClause fromClause) { if (fromClause == null) { return Collections.emptyList(); } @@ -114,7 +121,7 @@ public class SqlppVariableUtil { return bindingVars; } - public static Collection<VariableExpr> getBindingVariables(FromTerm fromTerm) { + public static List<VariableExpr> getBindingVariables(FromTerm fromTerm) { List<VariableExpr> bindingVars = new ArrayList<>(); if (fromTerm == null) { return bindingVars; @@ -132,7 +139,7 @@ public class SqlppVariableUtil { return bindingVars; } - public static Collection<VariableExpr> getBindingVariables(GroupbyClause gbyClause) { + public static List<VariableExpr> getBindingVariables(GroupbyClause gbyClause) { List<VariableExpr> bindingVars = new ArrayList<>(); if (gbyClause == null) { return bindingVars; @@ -143,10 +150,12 @@ public class SqlppVariableUtil { bindingVars.add(var); } } - for (GbyVariableExpressionPair gbyKey : gbyClause.getDecorPairList()) { - VariableExpr var = gbyKey.getVar(); - if (var != null) { - bindingVars.add(var); + if (gbyClause.hasDecorList()) { + for (GbyVariableExpressionPair gbyKey : gbyClause.getDecorPairList()) { + VariableExpr var = gbyKey.getVar(); + if (var != null) { + bindingVars.add(var); + } } } if (gbyClause.hasWithMap()) { @@ -156,7 +165,7 @@ public class SqlppVariableUtil { return bindingVars; } - public static Collection<VariableExpr> getBindingVariables(List<LetClause> letClauses) { + public static List<VariableExpr> getBindingVariables(List<LetClause> letClauses) { List<VariableExpr> bindingVars = new ArrayList<>(); if (letClauses == null || letClauses.isEmpty()) { return bindingVars; @@ -167,4 +176,18 @@ public class SqlppVariableUtil { return bindingVars; } + public static Map<Expression, Identifier> createFieldVariableMap(List<Pair<Expression, Identifier>> fieldList) { + Map<Expression, Identifier> fieldVars = new HashMap<>(); + for (Pair<Expression, Identifier> p : fieldList) { + fieldVars.put(p.first, p.second); + } + return fieldVars; + } + + public static void addToFieldVariableList(VariableExpr varExpr, List<Pair<Expression, Identifier>> outFieldList) { + VarIdentifier var = varExpr.getVar(); + VariableExpr newVarExpr = new VariableExpr(var); + newVarExpr.setSourceLocation(varExpr.getSourceLocation()); + outFieldList.add(new Pair<>(newVarExpr, toUserDefinedVariableName(var))); + } } http://git-wip-us.apache.org/repos/asf/asterixdb/blob/f2c18aa9/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/CheckSql92AggregateVisitor.java ---------------------------------------------------------------------- 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 6caf0f6..2caaa0c 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 @@ -44,6 +44,7 @@ import org.apache.asterix.lang.common.expression.UnaryExpr; import org.apache.asterix.lang.common.expression.VariableExpr; import org.apache.asterix.lang.common.statement.FunctionDecl; import org.apache.asterix.lang.common.statement.Query; +import org.apache.asterix.lang.common.struct.Identifier; import org.apache.asterix.lang.sqlpp.clause.FromClause; import org.apache.asterix.lang.sqlpp.clause.FromTerm; import org.apache.asterix.lang.sqlpp.clause.HavingClause; @@ -61,12 +62,16 @@ import org.apache.asterix.lang.sqlpp.expression.SelectExpression; import org.apache.asterix.lang.sqlpp.expression.WindowExpression; import org.apache.asterix.lang.sqlpp.util.FunctionMapUtil; import org.apache.asterix.lang.sqlpp.visitor.base.AbstractSqlppQueryExpressionVisitor; +import org.apache.hyracks.algebricks.common.utils.Pair; /** * This visitor checks if a non-subquery language construct contains SQL-92 aggregates. */ public class CheckSql92AggregateVisitor extends AbstractSqlppQueryExpressionVisitor<Boolean, ILangExpression> { + public CheckSql92AggregateVisitor() { + } + @Override public Boolean visit(Query q, ILangExpression parentSelectBlock) throws CompilationException { return false; @@ -289,7 +294,23 @@ public class CheckSql92AggregateVisitor extends AbstractSqlppQueryExpressionVisi return false; } - private Boolean visitExprList(List<Expression> exprs, ILangExpression parentSelectBlock) + @Override + public Boolean visit(CaseExpression caseExpr, ILangExpression arg) throws CompilationException { + return caseExpr.getConditionExpr().accept(this, arg) || visitExprList(caseExpr.getWhenExprs(), arg) + || visitExprList(caseExpr.getThenExprs(), arg) || caseExpr.getElseExpr().accept(this, arg); + } + + @Override + public Boolean visit(WindowExpression winExpr, ILangExpression arg) throws CompilationException { + return (winExpr.hasPartitionList() && visitExprList(winExpr.getPartitionList(), arg)) + || (winExpr.hasOrderByList() && visitExprList(winExpr.getOrderbyList(), arg)) + || (winExpr.hasFrameStartExpr() && winExpr.getFrameStartExpr().accept(this, arg)) + || (winExpr.hasFrameEndExpr() && winExpr.getFrameEndExpr().accept(this, arg)) + || (winExpr.hasWindowFieldList() && visitFieldList(winExpr.getWindowFieldList(), arg)) + || visitExprList(winExpr.getExprList(), arg); + } + + private boolean visitExprList(List<Expression> exprs, ILangExpression parentSelectBlock) throws CompilationException { for (Expression item : exprs) { if (item.accept(this, parentSelectBlock)) { @@ -299,16 +320,13 @@ public class CheckSql92AggregateVisitor extends AbstractSqlppQueryExpressionVisi return false; } - @Override - public Boolean visit(CaseExpression caseExpr, ILangExpression arg) throws CompilationException { - return caseExpr.getConditionExpr().accept(this, arg) || visitExprList(caseExpr.getWhenExprs(), arg) - || visitExprList(caseExpr.getThenExprs(), arg) || caseExpr.getElseExpr().accept(this, arg); - } - - @Override - public Boolean visit(WindowExpression winExpr, ILangExpression arg) throws CompilationException { - return winExpr.getExpr().accept(this, arg) - || (winExpr.hasPartitionList() && visitExprList(winExpr.getPartitionList(), arg)) - || visitExprList(winExpr.getOrderbyList(), arg); + private boolean visitFieldList(List<Pair<Expression, Identifier>> fieldList, ILangExpression parentSelectBlock) + throws CompilationException { + for (Pair<Expression, Identifier> p : fieldList) { + if (p.first.accept(this, parentSelectBlock)) { + return true; + } + } + return false; } } http://git-wip-us.apache.org/repos/asf/asterixdb/blob/f2c18aa9/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/CheckSubqueryVisitor.java ---------------------------------------------------------------------- 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 e1647ea..c816d05 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 @@ -19,6 +19,7 @@ package org.apache.asterix.lang.sqlpp.visitor; +import java.util.Collection; import java.util.List; import org.apache.asterix.common.exceptions.CompilationException; @@ -117,8 +118,8 @@ public class CheckSubqueryVisitor extends AbstractSqlppQueryExpressionVisitor<Bo public Boolean visit(SelectBlock selectBlock, ILangExpression arg) throws CompilationException { boolean hasSubquery = visit(selectBlock.getFromClause(), arg) || visit(selectBlock.getGroupbyClause(), arg) || visit(selectBlock.getHavingClause(), arg) || visit(selectBlock.getWhereClause(), arg); - return hasSubquery || visit(selectBlock.getSelectClause(), arg) || visit(selectBlock.getLetList(), arg) - || visit(selectBlock.getLetListAfterGroupby(), arg); + return hasSubquery || visit(selectBlock.getSelectClause(), arg) || visitExprList(selectBlock.getLetList(), arg) + || visitExprList(selectBlock.getLetListAfterGroupby(), arg); } @Override @@ -133,7 +134,7 @@ public class CheckSubqueryVisitor extends AbstractSqlppQueryExpressionVisitor<Bo @Override public Boolean visit(SelectRegular selectRegular, ILangExpression arg) throws CompilationException { - return visit(selectRegular.getProjections(), arg); + return visitExprList(selectRegular.getProjections(), arg); } @Override @@ -154,7 +155,7 @@ public class CheckSubqueryVisitor extends AbstractSqlppQueryExpressionVisitor<Bo if (selectStatement.isSubquery()) { return true; } - return visit(selectStatement.getLetList(), arg) || visit(selectStatement.getSelectSetOperation(), arg) + return visitExprList(selectStatement.getLetList(), arg) || visit(selectStatement.getSelectSetOperation(), arg) || visit(selectStatement.getOrderbyClause(), arg) || visit(selectStatement.getLimitClause(), arg); } @@ -171,8 +172,8 @@ public class CheckSubqueryVisitor extends AbstractSqlppQueryExpressionVisitor<Bo @Override public Boolean visit(CaseExpression caseExpression, ILangExpression arg) throws CompilationException { - return visit(caseExpression.getConditionExpr(), arg) || visit(caseExpression.getWhenExprs(), arg) - || visit(caseExpression.getThenExprs(), arg) || visit(caseExpression.getElseExpr(), arg); + return visit(caseExpression.getConditionExpr(), arg) || visitExprList(caseExpression.getWhenExprs(), arg) + || visitExprList(caseExpression.getThenExprs(), arg) || visit(caseExpression.getElseExpr(), arg); } @Override @@ -197,7 +198,7 @@ public class CheckSubqueryVisitor extends AbstractSqlppQueryExpressionVisitor<Bo @Override public Boolean visit(ListConstructor lc, ILangExpression arg) throws CompilationException { - return visit(lc.getExprList(), arg); + return visitExprList(lc.getExprList(), arg); } @Override @@ -215,7 +216,7 @@ public class CheckSubqueryVisitor extends AbstractSqlppQueryExpressionVisitor<Bo @Override public Boolean visit(OperatorExpr operatorExpr, ILangExpression arg) throws CompilationException { - return visit(operatorExpr.getExprList(), arg); + return visitExprList(operatorExpr.getExprList(), arg); } @Override @@ -261,7 +262,7 @@ public class CheckSubqueryVisitor extends AbstractSqlppQueryExpressionVisitor<Bo @Override public Boolean visit(OrderbyClause oc, ILangExpression arg) throws CompilationException { - return visit(oc.getOrderbyList(), arg); + return visitExprList(oc.getOrderbyList(), arg); } @Override @@ -271,15 +272,18 @@ public class CheckSubqueryVisitor extends AbstractSqlppQueryExpressionVisitor<Bo return true; } } - for (GbyVariableExpressionPair key : gc.getDecorPairList()) { - if (visit(key.getExpr(), arg)) { - return true; + if (gc.hasDecorList()) { + for (GbyVariableExpressionPair key : gc.getDecorPairList()) { + if (visit(key.getExpr(), arg)) { + return true; + } } } - for (Pair<Expression, Identifier> field : gc.getGroupFieldList()) { - if (visit(field.first, arg)) { - return true; - } + if (gc.hasGroupFieldList() && visitFieldList(gc.getGroupFieldList(), arg)) { + return true; + } + if (gc.hasWithMap() && visitExprList(gc.getWithVarMap().keySet(), arg)) { + return true; } return false; } @@ -296,29 +300,43 @@ public class CheckSubqueryVisitor extends AbstractSqlppQueryExpressionVisitor<Bo @Override public Boolean visit(WindowExpression winExpr, ILangExpression arg) throws CompilationException { - return visit(winExpr.getExpr(), arg) || (winExpr.hasPartitionList() && visit(winExpr.getPartitionList(), arg)) - || visit(winExpr.getOrderbyList(), arg); + return (winExpr.hasPartitionList() && visitExprList(winExpr.getPartitionList(), arg)) + || (winExpr.hasOrderByList() && visitExprList(winExpr.getOrderbyList(), arg)) + || (winExpr.hasFrameStartExpr() && visit(winExpr.getFrameStartExpr(), arg)) + || (winExpr.hasFrameEndExpr() && visit(winExpr.getFrameEndExpr(), arg)) + || (winExpr.hasWindowFieldList() && visitFieldList(winExpr.getWindowFieldList(), arg)) + || visitExprList(winExpr.getExprList(), arg); } @Override public Boolean visit(CallExpr callExpr, ILangExpression arg) throws CompilationException { - return visit(callExpr.getExprList(), arg); + return visitExprList(callExpr.getExprList(), arg); } - private boolean visit(List<?> langExprs, ILangExpression arg) throws CompilationException { - for (Object o : langExprs) { - ILangExpression langExpr = (ILangExpression) o; - if (langExpr.accept(this, arg)) { + private boolean visit(ILangExpression expr, ILangExpression arg) throws CompilationException { + if (expr == null) { + return false; + } + return expr.accept(this, arg); + } + + private <T extends ILangExpression> boolean visitExprList(Collection<T> exprList, ILangExpression arg) + throws CompilationException { + for (T langExpr : exprList) { + if (visit(langExpr, arg)) { return true; } } return false; } - private boolean visit(ILangExpression langExpr, ILangExpression arg) throws CompilationException { - if (langExpr == null) { - return false; + private <T extends ILangExpression> boolean visitFieldList(Collection<Pair<T, Identifier>> fieldList, + ILangExpression arg) throws CompilationException { + for (Pair<T, Identifier> p : fieldList) { + if (visit(p.first, arg)) { + return true; + } } - return langExpr.accept(this, arg); + return false; } } http://git-wip-us.apache.org/repos/asf/asterixdb/blob/f2c18aa9/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/DeepCopyVisitor.java ---------------------------------------------------------------------- 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 90cfab9..ed92bfd 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 @@ -293,30 +293,32 @@ public class DeepCopyVisitor extends AbstractSqlppQueryExpressionVisitor<ILangEx @Override public GroupbyClause visit(GroupbyClause gc, Void arg) throws CompilationException { List<GbyVariableExpressionPair> gbyPairList = new ArrayList<>(); - List<GbyVariableExpressionPair> decorPairList = new ArrayList<>(); - Map<Expression, VariableExpr> withVarMap = new HashMap<>(); - VariableExpr groupVarExpr = null; - List<Pair<Expression, Identifier>> groupFieldList = new ArrayList<>(); for (GbyVariableExpressionPair gbyVarExpr : gc.getGbyPairList()) { VariableExpr var = gbyVarExpr.getVar(); gbyPairList.add(new GbyVariableExpressionPair(var == null ? null : (VariableExpr) var.accept(this, arg), (Expression) gbyVarExpr.getExpr().accept(this, arg))); } - for (GbyVariableExpressionPair gbyVarExpr : gc.getDecorPairList()) { - VariableExpr var = gbyVarExpr.getVar(); - decorPairList.add(new GbyVariableExpressionPair(var == null ? null : (VariableExpr) var.accept(this, arg), - (Expression) gbyVarExpr.getExpr().accept(this, arg))); + List<GbyVariableExpressionPair> decorPairList = new ArrayList<>(); + if (gc.hasDecorList()) { + for (GbyVariableExpressionPair gbyVarExpr : gc.getDecorPairList()) { + VariableExpr var = gbyVarExpr.getVar(); + decorPairList + .add(new GbyVariableExpressionPair(var == null ? null : (VariableExpr) var.accept(this, arg), + (Expression) gbyVarExpr.getExpr().accept(this, arg))); + } } - for (Entry<Expression, VariableExpr> entry : gc.getWithVarMap().entrySet()) { - withVarMap.put((Expression) entry.getKey().accept(this, arg), - (VariableExpr) entry.getValue().accept(this, arg)); + Map<Expression, VariableExpr> withVarMap = new HashMap<>(); + if (gc.hasWithMap()) { + for (Entry<Expression, VariableExpr> entry : gc.getWithVarMap().entrySet()) { + withVarMap.put((Expression) entry.getKey().accept(this, arg), + (VariableExpr) entry.getValue().accept(this, arg)); + } } + VariableExpr groupVarExpr = null; if (gc.hasGroupVar()) { groupVarExpr = (VariableExpr) gc.getGroupVar().accept(this, arg); } - for (Pair<Expression, Identifier> field : gc.getGroupFieldList()) { - groupFieldList.add(new Pair<>((Expression) field.first.accept(this, arg), field.second)); - } + List<Pair<Expression, Identifier>> groupFieldList = copyFieldList(gc.getGroupFieldList(), arg); GroupbyClause copy = new GroupbyClause(gbyPairList, decorPairList, withVarMap, groupVarExpr, groupFieldList, gc.hasHashGroupByHint(), gc.isGroupAll()); copy.setSourceLocation(gc.getSourceLocation()); @@ -515,12 +517,24 @@ public class DeepCopyVisitor extends AbstractSqlppQueryExpressionVisitor<ILangEx @Override public ILangExpression visit(WindowExpression winExpr, Void arg) throws CompilationException { - Expression newExpr = (Expression) winExpr.getExpr().accept(this, arg); + List<Expression> newExprList = copyExprList(winExpr.getExprList(), arg); List<Expression> newPartitionList = winExpr.hasPartitionList() ? copyExprList(winExpr.getPartitionList(), arg) : null; - List<Expression> newOrderbyList = copyExprList(winExpr.getOrderbyList(), arg); - List<OrderbyClause.OrderModifier> newOrderbyModifierList = new ArrayList<>(winExpr.getOrderbyModifierList()); - WindowExpression copy = new WindowExpression(newExpr, newPartitionList, newOrderbyList, newOrderbyModifierList); + List<Expression> newOrderbyList = winExpr.hasOrderByList() ? copyExprList(winExpr.getOrderbyList(), arg) : null; + List<OrderbyClause.OrderModifier> newOrderbyModifierList = + winExpr.hasOrderByList() ? new ArrayList<>(winExpr.getOrderbyModifierList()) : null; + Expression newFrameStartExpr = + winExpr.hasFrameStartExpr() ? (Expression) winExpr.getFrameStartExpr().accept(this, arg) : null; + Expression newFrameEndExpr = + winExpr.hasFrameEndExpr() ? (Expression) winExpr.getFrameEndExpr().accept(this, arg) : null; + VariableExpr newWindowVar = + winExpr.hasWindowVar() ? (VariableExpr) winExpr.getWindowVar().accept(this, arg) : null; + List<Pair<Expression, Identifier>> newWindowFieldList = + winExpr.hasWindowFieldList() ? copyFieldList(winExpr.getWindowFieldList(), arg) : null; + WindowExpression copy = new WindowExpression(winExpr.getFunctionSignature(), newExprList, newPartitionList, + newOrderbyList, newOrderbyModifierList, winExpr.getFrameMode(), winExpr.getFrameStartKind(), + newFrameStartExpr, winExpr.getFrameEndKind(), newFrameEndExpr, winExpr.getFrameExclusionKind(), + newWindowVar, newWindowFieldList); copy.setSourceLocation(winExpr.getSourceLocation()); copy.addHints(winExpr.getHints()); return copy; @@ -533,4 +547,13 @@ public class DeepCopyVisitor extends AbstractSqlppQueryExpressionVisitor<ILangEx } return newExprList; } + + private List<Pair<Expression, Identifier>> copyFieldList(List<Pair<Expression, Identifier>> fieldList, Void arg) + throws CompilationException { + List<Pair<Expression, Identifier>> newFieldList = new ArrayList<>(fieldList.size()); + for (Pair<Expression, Identifier> field : fieldList) { + newFieldList.add(new Pair<>((Expression) field.first.accept(this, arg), field.second)); + } + return newFieldList; + } } http://git-wip-us.apache.org/repos/asf/asterixdb/blob/f2c18aa9/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/FreeVariableVisitor.java ---------------------------------------------------------------------- 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 dfa1430..b61f4e6 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 @@ -287,14 +287,21 @@ public class FreeVariableVisitor extends AbstractSqlppQueryExpressionVisitor<Voi for (GbyVariableExpressionPair gbyVarExpr : gc.getGbyPairList()) { gbyVarExpr.getExpr().accept(this, freeVars); } - for (GbyVariableExpressionPair decorVarExpr : gc.getDecorPairList()) { - decorVarExpr.getExpr().accept(this, freeVars); + if (gc.hasDecorList()) { + for (GbyVariableExpressionPair decorVarExpr : gc.getDecorPairList()) { + decorVarExpr.getExpr().accept(this, freeVars); + } } if (gc.hasGroupFieldList()) { for (Pair<Expression, Identifier> groupField : gc.getGroupFieldList()) { groupField.first.accept(this, freeVars); } } + if (gc.hasWithMap()) { + for (Expression expr : gc.getWithVarMap().keySet()) { + expr.accept(this, freeVars); + } + } return null; } @@ -440,11 +447,27 @@ public class FreeVariableVisitor extends AbstractSqlppQueryExpressionVisitor<Voi @Override public Void visit(WindowExpression winExpr, Collection<VariableExpr> freeVars) throws CompilationException { - winExpr.getExpr().accept(this, freeVars); if (winExpr.hasPartitionList()) { visit(winExpr.getPartitionList(), freeVars); } - visit(winExpr.getOrderbyList(), freeVars); + if (winExpr.hasOrderByList()) { + visit(winExpr.getOrderbyList(), freeVars); + } + if (winExpr.hasFrameStartExpr()) { + winExpr.getFrameStartExpr().accept(this, freeVars); + } + if (winExpr.hasFrameEndExpr()) { + winExpr.getFrameEndExpr().accept(this, freeVars); + } + if (winExpr.hasWindowFieldList()) { + for (Pair<Expression, Identifier> field : winExpr.getWindowFieldList()) { + field.first.accept(this, freeVars); + } + } + visit(winExpr.getExprList(), freeVars); + if (winExpr.hasWindowVar()) { + freeVars.remove(winExpr.getWindowVar()); + } return null; } http://git-wip-us.apache.org/repos/asf/asterixdb/blob/f2c18aa9/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/visitor/SqlppAstPrintVisitor.java ---------------------------------------------------------------------- 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 c12914d..f1039ff 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 @@ -293,12 +293,7 @@ public class SqlppAstPrintVisitor extends QueryPrintVisitor implements ISqlppVis out.print(skip(step + 1) + "GROUP AS "); gc.getGroupVar().accept(this, 0); if (gc.hasGroupFieldList()) { - out.println(skip(step + 1) + "("); - for (Pair<Expression, Identifier> field : gc.getGroupFieldList()) { - out.print(skip(step + 2) + field.second + ":="); - field.first.accept(this, 0); - } - out.println(skip(step + 1) + ")"); + printFieldList(step + 1, gc.getGroupFieldList()); } } if (gc.hasWithMap()) { @@ -335,31 +330,6 @@ public class SqlppAstPrintVisitor extends QueryPrintVisitor implements ISqlppVis } @Override - public Void visit(WindowExpression winExpr, Integer step) throws CompilationException { - out.print(skip(step) + "WINDOW"); - winExpr.getExpr().accept(this, step + 1); - out.println(); - out.println(skip(step) + "OVER ("); - if (winExpr.hasPartitionList()) { - out.println(skip(step + 1) + "PARTITION BY"); - List<Expression> partitionList = winExpr.getPartitionList(); - for (Expression expr : partitionList) { - expr.accept(this, step + 2); - out.println(); - } - } - out.println(skip(step + 1) + "ORDER BY"); - List<Expression> orderbyList = winExpr.getOrderbyList(); - List<OrderbyClause.OrderModifier> orderbyModifierList = winExpr.getOrderbyModifierList(); - for (int i = 0, ln = orderbyList.size(); i < ln; i++) { - orderbyList.get(i).accept(this, step + 2); - out.println(" " + orderbyModifierList.get(i)); - } - 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); @@ -376,4 +346,58 @@ public class SqlppAstPrintVisitor extends QueryPrintVisitor implements ISqlppVis out.println(skip(step) + "]"); return null; } + + @Override + public Void visit(WindowExpression winExpr, Integer step) throws CompilationException { + out.println(skip(step) + "WINDOW " + winExpr.getFunctionSignature() + "["); + for (Expression expr : winExpr.getExprList()) { + expr.accept(this, step + 1); + } + out.println(skip(step) + "]"); + if (winExpr.hasWindowVar()) { + out.print(skip(step + 1) + "AS "); + winExpr.getWindowVar().accept(this, 0); + if (winExpr.hasWindowFieldList()) { + printFieldList(step + 1, winExpr.getWindowFieldList()); + } + } + out.println(skip(step) + "OVER ("); + if (winExpr.hasPartitionList()) { + out.println(skip(step + 1) + "PARTITION BY"); + List<Expression> partitionList = winExpr.getPartitionList(); + for (Expression expr : partitionList) { + expr.accept(this, step + 2); + } + } + if (winExpr.hasOrderByList()) { + out.println(skip(step + 1) + "ORDER BY"); + List<Expression> orderbyList = winExpr.getOrderbyList(); + List<OrderbyClause.OrderModifier> orderbyModifierList = winExpr.getOrderbyModifierList(); + for (int i = 0, ln = orderbyList.size(); i < ln; i++) { + orderbyList.get(i).accept(this, step + 2); + out.println(skip(step + 2) + orderbyModifierList.get(i)); + } + } + if (winExpr.hasFrameDefinition()) { + out.println(skip(step + 1) + winExpr.getFrameMode() + ' ' + winExpr.getFrameStartKind() + ' ' + + winExpr.getFrameEndKind() + " EXCLUDE " + winExpr.getFrameExclusionKind()); + if (winExpr.hasFrameStartExpr()) { + winExpr.getFrameStartExpr().accept(this, step + 2); + } + if (winExpr.hasFrameEndExpr()) { + winExpr.getFrameEndExpr().accept(this, step + 2); + } + } + out.println(skip(step) + ")"); + return null; + } + + private void printFieldList(int step, List<Pair<Expression, Identifier>> fieldList) throws CompilationException { + out.println(skip(step) + "("); + for (Pair<Expression, Identifier> field : fieldList) { + out.print(skip(step + 1) + field.second + ":="); + field.first.accept(this, 0); + } + out.println(skip(step) + ")"); + } }
