blob: ce0d0a1fe55eea7c1470f45129e4043b62706c3e [file] [log] [blame]
/*
* 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.visitor;
import java.util.ArrayList;
import java.util.List;
import org.apache.asterix.common.exceptions.CompilationException;
import org.apache.asterix.lang.common.base.AbstractClause;
import org.apache.asterix.lang.common.base.Clause.ClauseType;
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.VariableExpr;
import org.apache.asterix.lang.common.rewrites.LangRewritingContext;
import org.apache.asterix.lang.common.rewrites.VariableSubstitutionEnvironment;
import org.apache.asterix.lang.common.struct.Identifier;
import org.apache.asterix.lang.common.util.VariableCloneAndSubstitutionUtil;
import org.apache.asterix.lang.common.visitor.CloneAndSubstituteVariablesVisitor;
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.HavingClause;
import org.apache.asterix.lang.sqlpp.clause.JoinClause;
import org.apache.asterix.lang.sqlpp.clause.NestClause;
import org.apache.asterix.lang.sqlpp.clause.Projection;
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.SelectRegular;
import org.apache.asterix.lang.sqlpp.clause.SelectSetOperation;
import org.apache.asterix.lang.sqlpp.clause.UnnestClause;
import org.apache.asterix.lang.sqlpp.expression.CaseExpression;
import org.apache.asterix.lang.sqlpp.expression.SelectExpression;
import org.apache.asterix.lang.sqlpp.expression.WindowExpression;
import org.apache.asterix.lang.sqlpp.struct.SetOperationInput;
import org.apache.asterix.lang.sqlpp.struct.SetOperationRight;
import org.apache.asterix.lang.sqlpp.visitor.base.ISqlppVisitor;
import org.apache.hyracks.algebricks.common.utils.Pair;
public class SqlppCloneAndSubstituteVariablesVisitor extends CloneAndSubstituteVariablesVisitor implements
ISqlppVisitor<Pair<ILangExpression, VariableSubstitutionEnvironment>, VariableSubstitutionEnvironment> {
private LangRewritingContext context;
public SqlppCloneAndSubstituteVariablesVisitor(LangRewritingContext context) {
super(context);
this.context = context;
}
@Override
public Pair<ILangExpression, VariableSubstitutionEnvironment> visit(FromClause fromClause,
VariableSubstitutionEnvironment env) throws CompilationException {
VariableSubstitutionEnvironment currentEnv = new VariableSubstitutionEnvironment(env);
List<FromTerm> newFromTerms = new ArrayList<>();
for (FromTerm fromTerm : fromClause.getFromTerms()) {
Pair<ILangExpression, VariableSubstitutionEnvironment> p = fromTerm.accept(this, currentEnv);
newFromTerms.add((FromTerm) p.first);
// A right from term could be correlated from a left from term,
// therefore we propagate the substitution environment.
currentEnv = p.second;
}
FromClause newFromClause = new FromClause(newFromTerms);
newFromClause.setSourceLocation(fromClause.getSourceLocation());
return new Pair<>(newFromClause, currentEnv);
}
@Override
public Pair<ILangExpression, VariableSubstitutionEnvironment> visit(FromTerm fromTerm,
VariableSubstitutionEnvironment env) throws CompilationException {
VariableExpr leftVar = fromTerm.getLeftVariable();
VariableExpr newLeftVar = generateNewVariable(context, leftVar);
VariableExpr newLeftPosVar = fromTerm.hasPositionalVariable()
? generateNewVariable(context, fromTerm.getPositionalVariable()) : null;
Expression newLeftExpr = (Expression) visitUnnestBindingExpression(fromTerm.getLeftExpression(), env).first;
List<AbstractBinaryCorrelateClause> newCorrelateClauses = new ArrayList<>();
VariableSubstitutionEnvironment currentEnv = new VariableSubstitutionEnvironment(env);
currentEnv.removeSubstitution(newLeftVar);
if (newLeftPosVar != null) {
currentEnv.removeSubstitution(newLeftPosVar);
}
for (AbstractBinaryCorrelateClause correlateClause : fromTerm.getCorrelateClauses()) {
if (correlateClause.getClauseType() == ClauseType.UNNEST_CLAUSE) {
// The right-hand-side of unnest could be correlated with the left side,
// therefore we propagate the substitution environment of the left-side.
Pair<ILangExpression, VariableSubstitutionEnvironment> p = correlateClause.accept(this, currentEnv);
currentEnv = p.second;
newCorrelateClauses.add((AbstractBinaryCorrelateClause) p.first);
} else {
// The right-hand-side of join and nest could not be correlated with the left side,
// therefore we propagate the original substitution environment.
newCorrelateClauses.add((AbstractBinaryCorrelateClause) correlateClause.accept(this, env).first);
// Join binding variables should be removed for further traversal.
currentEnv.removeSubstitution(correlateClause.getRightVariable());
if (correlateClause.hasPositionalVariable()) {
currentEnv.removeSubstitution(correlateClause.getPositionalVariable());
}
}
}
FromTerm newFromTerm = new FromTerm(newLeftExpr, newLeftVar, newLeftPosVar, newCorrelateClauses);
newFromTerm.setSourceLocation(fromTerm.getSourceLocation());
return new Pair<>(newFromTerm, currentEnv);
}
@Override
public Pair<ILangExpression, VariableSubstitutionEnvironment> visit(JoinClause joinClause,
VariableSubstitutionEnvironment env) throws CompilationException {
VariableExpr rightVar = joinClause.getRightVariable();
VariableExpr newRightVar = generateNewVariable(context, rightVar);
VariableExpr newRightPosVar = joinClause.hasPositionalVariable()
? generateNewVariable(context, joinClause.getPositionalVariable()) : null;
// Visits the right expression.
Expression newRightExpr = (Expression) visitUnnestBindingExpression(joinClause.getRightExpression(), env).first;
// Visits the condition.
VariableSubstitutionEnvironment currentEnv = new VariableSubstitutionEnvironment(env);
currentEnv.removeSubstitution(newRightVar);
if (newRightPosVar != null) {
currentEnv.removeSubstitution(newRightPosVar);
}
// The condition can refer to the newRightVar and newRightPosVar.
Expression conditionExpr = (Expression) joinClause.getConditionExpression().accept(this, currentEnv).first;
JoinClause newJoinClause = new JoinClause(joinClause.getJoinType(), newRightExpr, newRightVar, newRightPosVar,
conditionExpr, joinClause.getOuterJoinMissingValueType());
newJoinClause.setSourceLocation(joinClause.getSourceLocation());
return new Pair<>(newJoinClause, currentEnv);
}
@Override
public Pair<ILangExpression, VariableSubstitutionEnvironment> visit(NestClause nestClause,
VariableSubstitutionEnvironment env) throws CompilationException {
VariableExpr rightVar = nestClause.getRightVariable();
VariableExpr newRightVar = generateNewVariable(context, rightVar);
VariableExpr newRightPosVar = nestClause.hasPositionalVariable()
? generateNewVariable(context, nestClause.getPositionalVariable()) : null;
// Visits the right expression.
Expression rightExpr = (Expression) nestClause.getRightExpression().accept(this, env).first;
// Visits the condition.
VariableSubstitutionEnvironment currentEnv = new VariableSubstitutionEnvironment(env);
currentEnv.removeSubstitution(newRightVar);
if (newRightPosVar != null) {
currentEnv.removeSubstitution(newRightPosVar);
}
// The condition can refer to the newRightVar and newRightPosVar.
Expression conditionExpr = (Expression) nestClause.getConditionExpression().accept(this, currentEnv).first;
NestClause newNestClause =
new NestClause(nestClause.getNestType(), rightExpr, newRightVar, newRightPosVar, conditionExpr);
newNestClause.setSourceLocation(nestClause.getSourceLocation());
return new Pair<>(newNestClause, currentEnv);
}
@Override
public Pair<ILangExpression, VariableSubstitutionEnvironment> visit(UnnestClause unnestClause,
VariableSubstitutionEnvironment env) throws CompilationException {
VariableExpr rightVar = unnestClause.getRightVariable();
VariableExpr newRightVar = generateNewVariable(context, rightVar);
VariableExpr newRightPosVar = unnestClause.hasPositionalVariable()
? generateNewVariable(context, unnestClause.getPositionalVariable()) : null;
// Visits the right expression.
Expression rightExpr = (Expression) visitUnnestBindingExpression(unnestClause.getRightExpression(), env).first;
// Visits the condition.
VariableSubstitutionEnvironment currentEnv = new VariableSubstitutionEnvironment(env);
currentEnv.removeSubstitution(newRightVar);
if (newRightPosVar != null) {
currentEnv.removeSubstitution(newRightPosVar);
}
// The condition can refer to the newRightVar and newRightPosVar.
UnnestClause newUnnestClause = new UnnestClause(unnestClause.getUnnestType(), rightExpr, newRightVar,
newRightPosVar, unnestClause.getOuterUnnestMissingValueType());
newUnnestClause.setSourceLocation(unnestClause.getSourceLocation());
return new Pair<>(newUnnestClause, currentEnv);
}
@Override
public Pair<ILangExpression, VariableSubstitutionEnvironment> visit(Projection projection,
VariableSubstitutionEnvironment env) throws CompilationException {
Projection newProjection = new Projection(projection.getKind(),
projection.hasExpression() ? (Expression) projection.getExpression().accept(this, env).first : null,
projection.getName());
newProjection.setSourceLocation(projection.getSourceLocation());
return new Pair<>(newProjection, env);
}
@Override
public Pair<ILangExpression, VariableSubstitutionEnvironment> visit(SelectBlock selectBlock,
VariableSubstitutionEnvironment env) throws CompilationException {
Pair<ILangExpression, VariableSubstitutionEnvironment> newFrom = null;
Pair<ILangExpression, VariableSubstitutionEnvironment> newLetWhere;
Pair<ILangExpression, VariableSubstitutionEnvironment> newGroupby = null;
Pair<ILangExpression, VariableSubstitutionEnvironment> newLetHaving;
Pair<ILangExpression, VariableSubstitutionEnvironment> newSelect;
List<AbstractClause> newLetWhereClauses = new ArrayList<>();
List<AbstractClause> newLetHavingClausesAfterGby = new ArrayList<>();
VariableSubstitutionEnvironment currentEnv = new VariableSubstitutionEnvironment(env);
if (selectBlock.hasFromClause()) {
newFrom = selectBlock.getFromClause().accept(this, currentEnv);
currentEnv = newFrom.second;
}
if (selectBlock.hasLetWhereClauses()) {
for (AbstractClause letWhereClause : selectBlock.getLetWhereList()) {
newLetWhere = letWhereClause.accept(this, currentEnv);
currentEnv = newLetWhere.second;
newLetWhereClauses.add((AbstractClause) newLetWhere.first);
}
}
if (selectBlock.hasGroupbyClause()) {
newGroupby = selectBlock.getGroupbyClause().accept(this, currentEnv);
currentEnv = newGroupby.second;
if (selectBlock.hasLetHavingClausesAfterGroupby()) {
for (AbstractClause letHavingClauseAfterGby : selectBlock.getLetHavingListAfterGroupby()) {
newLetHaving = letHavingClauseAfterGby.accept(this, currentEnv);
currentEnv = newLetHaving.second;
newLetHavingClausesAfterGby.add((AbstractClause) newLetHaving.first);
}
}
}
newSelect = selectBlock.getSelectClause().accept(this, currentEnv);
currentEnv = newSelect.second;
FromClause fromClause = newFrom == null ? null : (FromClause) newFrom.first;
GroupbyClause groupbyClause = newGroupby == null ? null : (GroupbyClause) newGroupby.first;
SelectBlock newSelectBlock = new SelectBlock((SelectClause) newSelect.first, fromClause, newLetWhereClauses,
groupbyClause, newLetHavingClausesAfterGby);
newSelectBlock.setSourceLocation(selectBlock.getSourceLocation());
return new Pair<>(newSelectBlock, currentEnv);
}
@Override
public Pair<ILangExpression, VariableSubstitutionEnvironment> visit(SelectClause selectClause,
VariableSubstitutionEnvironment env) throws CompilationException {
boolean distinct = selectClause.distinct();
if (selectClause.selectElement()) {
Pair<ILangExpression, VariableSubstitutionEnvironment> newSelectElement =
selectClause.getSelectElement().accept(this, env);
SelectClause newSelectClause = new SelectClause((SelectElement) newSelectElement.first, null, distinct);
newSelectClause.setSourceLocation(selectClause.getSourceLocation());
return new Pair<>(newSelectClause, newSelectElement.second);
} else {
Pair<ILangExpression, VariableSubstitutionEnvironment> newSelectRegular =
selectClause.getSelectRegular().accept(this, env);
SelectClause newSelectClause = new SelectClause(null, (SelectRegular) newSelectRegular.first, distinct);
newSelectClause.setSourceLocation(selectClause.getSourceLocation());
return new Pair<>(newSelectClause, newSelectRegular.second);
}
}
@Override
public Pair<ILangExpression, VariableSubstitutionEnvironment> visit(SelectElement selectElement,
VariableSubstitutionEnvironment env) throws CompilationException {
Pair<ILangExpression, VariableSubstitutionEnvironment> newExpr =
selectElement.getExpression().accept(this, env);
SelectElement newSelectElement = new SelectElement((Expression) newExpr.first);
newSelectElement.setSourceLocation(selectElement.getSourceLocation());
return new Pair<>(newSelectElement, newExpr.second);
}
@Override
public Pair<ILangExpression, VariableSubstitutionEnvironment> visit(SelectRegular selectRegular,
VariableSubstitutionEnvironment env) throws CompilationException {
List<Projection> newProjections = new ArrayList<>();
for (Projection projection : selectRegular.getProjections()) {
newProjections.add((Projection) projection.accept(this, env).first);
}
SelectRegular newSelectRegular = new SelectRegular(newProjections);
newSelectRegular.setSourceLocation(selectRegular.getSourceLocation());
return new Pair<>(newSelectRegular, env);
}
@Override
public Pair<ILangExpression, VariableSubstitutionEnvironment> visit(SelectSetOperation selectSetOperation,
VariableSubstitutionEnvironment env) throws CompilationException {
SetOperationInput leftInput = selectSetOperation.getLeftInput();
SetOperationInput newLeftInput;
Pair<ILangExpression, VariableSubstitutionEnvironment> leftResult;
// Sets the left input.
if (leftInput.selectBlock()) {
leftResult = leftInput.getSelectBlock().accept(this, env);
newLeftInput = new SetOperationInput((SelectBlock) leftResult.first, null);
} else {
leftResult = leftInput.getSubquery().accept(this, env);
newLeftInput = new SetOperationInput(null, (SelectExpression) leftResult.first);
}
// Sets the right input
List<SetOperationRight> newRightInputs = new ArrayList<>();
if (selectSetOperation.hasRightInputs()) {
for (SetOperationRight right : selectSetOperation.getRightInputs()) {
SetOperationInput newRightInput;
SetOperationInput rightInput = right.getSetOperationRightInput();
if (rightInput.selectBlock()) {
Pair<ILangExpression, VariableSubstitutionEnvironment> rightResult =
rightInput.getSelectBlock().accept(this, env);
newRightInput = new SetOperationInput((SelectBlock) rightResult.first, null);
} else {
Pair<ILangExpression, VariableSubstitutionEnvironment> rightResult =
rightInput.getSubquery().accept(this, env);
newRightInput = new SetOperationInput(null, (SelectExpression) rightResult.first);
}
newRightInputs.add(new SetOperationRight(right.getSetOpType(), right.isSetSemantics(), newRightInput));
}
}
SelectSetOperation newSelectSetOperation = new SelectSetOperation(newLeftInput, newRightInputs);
newSelectSetOperation.setSourceLocation(selectSetOperation.getSourceLocation());
return new Pair<>(newSelectSetOperation, selectSetOperation.hasRightInputs() ? env : leftResult.second);
}
@Override
public Pair<ILangExpression, VariableSubstitutionEnvironment> visit(SelectExpression selectExpression,
VariableSubstitutionEnvironment env) throws CompilationException {
boolean subquery = selectExpression.isSubquery();
List<LetClause> newLetList = new ArrayList<>();
SelectSetOperation newSelectSetOperation;
OrderbyClause newOrderbyClause = null;
LimitClause newLimitClause = null;
VariableSubstitutionEnvironment currentEnv = env;
Pair<ILangExpression, VariableSubstitutionEnvironment> p;
if (selectExpression.hasLetClauses()) {
for (LetClause letClause : selectExpression.getLetList()) {
p = letClause.accept(this, currentEnv);
newLetList.add((LetClause) p.first);
currentEnv = p.second;
}
}
p = selectExpression.getSelectSetOperation().accept(this, env);
newSelectSetOperation = (SelectSetOperation) p.first;
currentEnv = p.second;
if (selectExpression.hasOrderby()) {
p = selectExpression.getOrderbyClause().accept(this, currentEnv);
newOrderbyClause = (OrderbyClause) p.first;
currentEnv = p.second;
}
if (selectExpression.hasLimit()) {
p = selectExpression.getLimitClause().accept(this, currentEnv);
newLimitClause = (LimitClause) p.first;
currentEnv = p.second;
}
SelectExpression newSelectExpression =
new SelectExpression(newLetList, newSelectSetOperation, newOrderbyClause, newLimitClause, subquery);
newSelectExpression.setSourceLocation(selectExpression.getSourceLocation());
return new Pair<>(newSelectExpression, currentEnv);
}
@Override
public Pair<ILangExpression, VariableSubstitutionEnvironment> visit(HavingClause havingClause,
VariableSubstitutionEnvironment env) throws CompilationException {
Pair<ILangExpression, VariableSubstitutionEnvironment> p = havingClause.getFilterExpression().accept(this, env);
HavingClause newHavingClause = new HavingClause((Expression) p.first);
newHavingClause.setSourceLocation(havingClause.getSourceLocation());
return new Pair<>(newHavingClause, p.second);
}
@Override
public Pair<ILangExpression, VariableSubstitutionEnvironment> visit(CaseExpression caseExpr,
VariableSubstitutionEnvironment env) throws CompilationException {
Expression conditionExpr = (Expression) caseExpr.getConditionExpr().accept(this, env).first;
List<Expression> whenExprList =
VariableCloneAndSubstitutionUtil.visitAndCloneExprList(caseExpr.getWhenExprs(), env, this);
List<Expression> thenExprList =
VariableCloneAndSubstitutionUtil.visitAndCloneExprList(caseExpr.getThenExprs(), env, this);
Expression elseExpr = (Expression) caseExpr.getElseExpr().accept(this, env).first;
CaseExpression newCaseExpr = new CaseExpression(conditionExpr, whenExprList, thenExprList, elseExpr);
newCaseExpr.setSourceLocation(caseExpr.getSourceLocation());
return new Pair<>(newCaseExpr, env);
}
@Override
public Pair<ILangExpression, VariableSubstitutionEnvironment> visit(WindowExpression winExpr,
VariableSubstitutionEnvironment env) throws CompilationException {
List<Expression> newExprList =
VariableCloneAndSubstitutionUtil.visitAndCloneExprList(winExpr.getExprList(), env, this);
Expression newAggFilterExpr = winExpr.hasAggregateFilterExpr()
? (Expression) winExpr.getAggregateFilterExpr().accept(this, env).first : null;
List<Expression> newPartitionList = winExpr.hasPartitionList()
? VariableCloneAndSubstitutionUtil.visitAndCloneExprList(winExpr.getPartitionList(), env, this) : null;
List<Expression> newOrderbyList = winExpr.hasOrderByList()
? VariableCloneAndSubstitutionUtil.visitAndCloneExprList(winExpr.getOrderbyList(), env, this) : null;
List<OrderbyClause.OrderModifier> newOrderbyModifierList =
winExpr.hasOrderByList() ? new ArrayList<>(winExpr.getOrderbyModifierList()) : null;
List<OrderbyClause.NullOrderModifier> newOrderbyNullModifierList =
winExpr.hasOrderByList() ? new ArrayList<>(winExpr.getOrderbyNullModifierList()) : null;
Expression newFrameStartExpr =
winExpr.hasFrameStartExpr() ? (Expression) winExpr.getFrameStartExpr().accept(this, env).first : null;
Expression newFrameEndExpr =
winExpr.hasFrameEndExpr() ? (Expression) winExpr.getFrameEndExpr().accept(this, env).first : null;
VariableExpr newWindowVar =
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,
newAggFilterExpr, newPartitionList, newOrderbyList, newOrderbyModifierList, newOrderbyNullModifierList,
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);
}
}