15 package com.cloudera.impala.analysis;
17 import java.util.ArrayList;
18 import java.util.List;
20 import org.slf4j.Logger;
21 import org.slf4j.LoggerFactory;
26 import com.google.common.base.Preconditions;
27 import com.google.common.base.Predicates;
28 import com.google.common.collect.Lists;
35 private final static Logger
LOG = LoggerFactory.getLogger(StmtRewriter.class);
44 if (analysisResult.getStmt() instanceof
QueryStmt) {
47 rewrittenStmt = analyzedStmt.clone();
48 }
else if (analysisResult.getStmt() instanceof
InsertStmt) {
51 rewrittenStmt = ((
InsertStmt)analysisResult.getStmt()).clone();
58 Preconditions.checkNotNull(analysisResult.getTmpCreateTableStmt());
60 ctasStmt.getQueryStmt().clone());
63 analysisResult.getStmt().toSql());
74 Preconditions.checkNotNull(stmt);
81 stmt.getClass().getSimpleName() +
" statements");
93 for (
TableRef tblRef: stmt.tableRefs_) {
95 InlineViewRef inlineViewRef = (InlineViewRef)tblRef;
98 inlineViewRef.setRewrittenViewStmt(inlineViewRef.getViewStmt().clone());
101 if (stmt.hasWhereClause()) {
103 stmt.whereClause_ = Expr.pushNegationToOperands(stmt.whereClause_);
108 stmt.whereClause_.toSql());
112 stmt.sqlString_ = null;
113 LOG.trace(
"rewritten stmt: " + stmt.toSql());
123 Preconditions.checkState(operand.getQueryStmt() instanceof
SelectStmt);
124 StmtRewriter.rewriteSelectStatement(
125 (SelectStmt)operand.getQueryStmt(), operand.getAnalyzer());
136 return expr.contains(Subquery.class);
138 for (
Expr child: expr.getChildren()) {
200 int numTableRefs = stmt.tableRefs_.size();
201 ArrayList<Expr> exprsWithSubqueries = Lists.newArrayList();
209 List<Subquery> subqueries = Lists.newArrayList();
210 conjunct.collectAll(Predicates.instanceOf(Subquery.class), subqueries);
211 if (subqueries.size() == 0)
continue;
212 if (subqueries.size() > 1) {
214 "expression: " + conjunct.toSql());
220 "expression: " + conjunct.toSql());
228 if (boolLiteral != null) {
229 boolLiteral.analyze(analyzer);
230 smap.put(conjunct, boolLiteral);
238 boolLiteral.analyze(analyzer);
239 smap.put(conjunct, boolLiteral);
240 exprsWithSubqueries.add(conjunct);
242 stmt.whereClause_ = stmt.whereClause_.substitute(smap, analyzer,
false);
244 boolean hasNewVisibleTuple =
false;
247 for (
Expr expr: exprsWithSubqueries) {
249 hasNewVisibleTuple =
true;
252 if (
canEliminate(stmt.whereClause_)) stmt.whereClause_ = null;
262 Subquery subquery = predicate.getSubquery();
263 Preconditions.checkNotNull(subquery);
266 if (subqueryStmt.getAnalyzer().hasEmptyResultSet()) {
268 }
else if (subqueryStmt.hasAggInfo() && subqueryStmt.getAggInfo().hasAggregateExprs()
269 && !subqueryStmt.hasAnalyticInfo() && subqueryStmt.getHavingPred() == null) {
284 for (
int i = 0; i < expr.getChildren().size(); ++i) {
297 Subquery subquery = expr.getSubquery();
298 Preconditions.checkNotNull(subquery);
303 newSubquery.analyze(analyzer);
305 smap.put(subquery, newSubquery);
306 return expr.substitute(smap, analyzer,
false);
334 Preconditions.checkNotNull(expr);
335 Preconditions.checkNotNull(analyzer);
336 boolean updateSelectList =
false;
343 List<String> colLabels = Lists.newArrayList();
344 for (
int i = 0; i < subqueryStmt.getColLabels().size(); ++i) {
345 colLabels.add(subqueryStmt.getColumnAliasGenerator().getNextAlias());
348 stmt.getTableAliasGenerator().getNextAlias(), subqueryStmt, colLabels);
352 if (!onClauseConjuncts.isEmpty()) {
357 subqueryStmt.limitElement_ = null;
363 if (onClauseConjuncts.isEmpty()) subqueryStmt.
setLimit(1);
368 boolean updateGroupBy = expr.getSubquery().isScalarSubquery() ||
369 (expr instanceof ExistsPredicate &&
370 subqueryStmt.hasAggInfo() && !subqueryStmt.
getSelectList().isDistinct());
371 List<Expr> lhsExprs = Lists.newArrayList();
372 List<Expr> rhsExprs = Lists.newArrayList();
373 for (
Expr conjunct: onClauseConjuncts) {
375 lhsExprs, rhsExprs, updateGroupBy);
382 inlineView.analyze(analyzer);
383 inlineView.setLeftTblRef(stmt.tableRefs_.get(stmt.tableRefs_.size() - 1));
384 stmt.tableRefs_.add(inlineView);
389 !onClauseConjuncts.isEmpty());
390 if (joinConjunct != null) {
393 if (!onClauseConjuncts.isEmpty() &&
408 CompoundPredicate.createConjunction(joinConjunct, stmt.whereClause_);
411 updateSelectList =
true;
414 if (joinConjunct != null) onClauseConjuncts.add(joinConjunct);
418 Expr onClausePredicate =
419 CompoundPredicate.createConjunctivePredicate(onClauseConjuncts);
421 if (onClausePredicate == null) {
422 Preconditions.checkState(expr instanceof ExistsPredicate);
424 if (((ExistsPredicate)expr).isNotExists()) {
426 subqueryStmt.
toSql());
433 LOG.warn(
"uncorrelated subquery rewritten using a cross join");
441 Preconditions.checkState(lhsExprs.size() == rhsExprs.size());
442 for (
int i = 0; i < lhsExprs.size(); ++i) {
443 Expr lhsExpr = lhsExprs.get(i);
444 Expr rhsExpr = rhsExprs.get(i);
445 rhsExpr.analyze(analyzer);
446 smap.put(lhsExpr, rhsExpr);
448 onClausePredicate = onClausePredicate.substitute(smap, analyzer,
false);
454 subqueryStmt.
toSql());
458 boolean hasEqJoinPred =
false;
461 ((BinaryPredicate)conjunct).getOp() != BinaryPredicate.Operator.EQ) {
464 List<TupleId> lhsTupleIds = Lists.newArrayList();
465 conjunct.getChild(0).getIds(lhsTupleIds, null);
466 if (lhsTupleIds.isEmpty())
continue;
467 List<TupleId> rhsTupleIds = Lists.newArrayList();
468 conjunct.getChild(1).getIds(rhsTupleIds, null);
469 if (rhsTupleIds.isEmpty())
continue;
472 if ((lhsTupleIds.contains(inlineView.
getDesc().getId()) && lhsTupleIds.size() > 1)
473 || (rhsTupleIds.contains(inlineView.getDesc().getId())
474 && rhsTupleIds.size() > 1)) {
477 hasEqJoinPred =
true;
481 if (!hasEqJoinPred) {
485 if (!expr.getSubquery().isScalarSubquery() ||
486 (!(hasGroupBy && stmt.selectList_.isDistinct()) && hasGroupBy)) {
494 CompoundPredicate.createConjunction(onClausePredicate, stmt.whereClause_);
503 expr instanceof ExistsPredicate && ((ExistsPredicate)expr).isNotExists()) {
508 List<TupleId> tIds = Lists.newArrayList();
509 joinConjunct.getIds(tIds, null);
510 if (tIds.size() <= 1 || !tIds.contains(inlineView.getDesc().getId())) {
517 if (conjunct.equals(joinConjunct)) {
521 ((
BinaryPredicate)conjunct).setOp(BinaryPredicate.Operator.NULL_MATCHING_EQ);
529 inlineView.setJoinOp(joinOp);
530 inlineView.setOnClause(onClausePredicate);
531 return updateSelectList;
541 Preconditions.checkState(tableIdx < stmt.tableRefs_.size());
542 ArrayList<SelectListItem> newItems = Lists.newArrayList();
543 for (
int i = 0; i < stmt.selectList_.getItems().size(); ++i) {
545 if (!item.
isStar() || item.getRawPath() != null) {
551 for (
int j = 0; j < tableIdx; ++j) {
552 TableRef tableRef = stmt.tableRefs_.get(j);
553 if (tableRef.
getJoinOp() == JoinOperator.LEFT_SEMI_JOIN ||
557 newItems.add(SelectListItem.createStarItem(
558 Lists.newArrayList(tableRef.getUniqueAlias())));
561 Preconditions.checkState(!newItems.isEmpty());
562 boolean isDistinct = stmt.selectList_.isDistinct();
585 List<TupleId> subqueryTupleIds = subqueryStmt.getTableRefIds();
586 ArrayList<Expr> correlatedPredicates = Lists.newArrayList();
588 if (subqueryStmt.hasWhereClause()) {
592 "are not supported: " + subqueryStmt.getWhereClause().toSql());
597 subqueryTupleIds, correlatedPredicates);
598 if (
canEliminate(newWhereClause)) newWhereClause = null;
599 subqueryStmt.setWhereClause(newWhereClause);
603 for (
TableRef tableRef: subqueryStmt.getTableRefs()) {
604 if (tableRef.getOnClause() == null)
continue;
606 ArrayList<Expr> onClauseCorrelatedPreds = Lists.newArrayList();
608 subqueryTupleIds, onClauseCorrelatedPreds);
609 if (onClauseCorrelatedPreds.isEmpty())
continue;
611 correlatedPredicates.addAll(onClauseCorrelatedPreds);
618 tableRef.setOnClause(null);
620 tableRef.setOnClause(newOnClause);
623 return correlatedPredicates;
632 ArrayList<Expr> matches) {
637 for (
int i = 0; i < root.getChildren().size(); ++i) {
652 Preconditions.checkNotNull(expr);
653 Preconditions.checkState(expr.contains(Subquery.class));
655 Preconditions.checkNotNull(stmt);
661 && (stmt.
hasAggInfo() || stmt.hasAnalyticInfo()))) {
663 "and/or aggregation: " + stmt.
toSql());
670 stmt.selectList_.isDistinct()) &&
673 "LIMIT clause: " + stmt.
toSql());
687 List<TupleId> parentQueryTids, List<Expr> lhsExprs, List<Expr> rhsExprs,
690 List<TupleId> subqueryTblIds = stmt.getTableRefIds();
691 ArrayList<Expr> groupByExprs = null;
692 if (updateGroupBy) groupByExprs = Lists.newArrayList();
694 List<SelectListItem> items = stmt.selectList_.getItems();
697 ArrayList<Expr> slotRefs = Lists.newArrayList();
698 expr.collectAll(Predicates.instanceOf(SlotRef.class), slotRefs);
699 List<Expr> exprsBoundBySubqueryTids = Lists.newArrayList();
700 for (
Expr slotRef: slotRefs) {
701 if (slotRef.isBoundByTupleIds(subqueryTblIds)) {
702 exprsBoundBySubqueryTids.add(slotRef);
707 if (exprsBoundBySubqueryTids.isEmpty())
return;
710 Expr exprBoundBySubqueryTids = null;
711 if (exprsBoundBySubqueryTids.size() > 1) {
714 if (expr.getChild(0).isBoundByTupleIds(subqueryTblIds) &&
715 expr.getChild(1).isBoundByTupleIds(parentQueryTids)) {
716 exprBoundBySubqueryTids = expr.getChild(0);
717 }
else if (expr.getChild(0).isBoundByTupleIds(parentQueryTids) &&
718 expr.getChild(1).isBoundByTupleIds(subqueryTblIds)) {
719 exprBoundBySubqueryTids = expr.getChild(1);
722 "that participate in a predicate must be on the same side of " +
723 "that predicate: " + expr.toSql());
726 Preconditions.checkState(exprsBoundBySubqueryTids.size() == 1);
727 exprBoundBySubqueryTids = exprsBoundBySubqueryTids.get(0);
729 exprsBoundBySubqueryTids.clear();
730 exprsBoundBySubqueryTids.add(exprBoundBySubqueryTids);
738 for (
Expr boundExpr: exprsBoundBySubqueryTids) {
739 String colAlias = stmt.getColumnAliasGenerator().getNextAlias();
741 inlineView.getExplicitColLabels().add(colAlias);
742 lhsExprs.add(boundExpr);
743 rhsExprs.add(
new SlotRef(Lists.newArrayList(inlineView.getUniqueAlias(), colAlias)));
744 if (groupByExprs != null) groupByExprs.add(boundExpr);
748 boolean isDistinct = stmt.selectList_.isDistinct();
752 if (groupByExprs != null && !groupByExprs.isEmpty()) {
754 stmt.groupingExprs_.addAll(groupByExprs);
756 stmt.groupingExprs_ = groupByExprs;
766 List<TupleId> subqueryTupleIds) {
771 for (
Expr child: expr.getChildren()) {
785 for (
Expr child: root.getChildren()) {
798 && !expr.isBoundByTupleIds(tupleIds);
811 Preconditions.checkNotNull(exprWithSubquery);
812 Preconditions.checkNotNull(inlineView);
813 Preconditions.checkState(exprWithSubquery.contains(Subquery.class));
817 inlineView.getUniqueAlias(), inlineView.getColLabels().
get(0)));
818 slotRef.analyze(analyzer);
819 Expr subquerySubstitute = slotRef;
822 exprWithSubquery.getChild(0), slotRef);
823 pred.analyze(analyzer);
827 Subquery subquery = exprWithSubquery.getSubquery();
834 ((
SelectStmt) inlineView.getViewStmt()).getSelectList().getItems().
get(0);
837 "correlated subqueries: " + subquery.
toSql());
847 "an empty input cannot be used in an expression in a " +
848 "correlated subquery's select list: " + subquery.
toSql());
851 List<Expr> aggFns = Lists.newArrayList();
858 Lists.newArrayList((
Expr) slotRef));
859 zeroIfNull.analyze(analyzer);
860 subquerySubstitute = zeroIfNull;
861 }
else if (((
FunctionCallExpr)aggFns.get(0)).getReturnType().isStringType()) {
862 List<Expr> params = Lists.newArrayList();
866 ifnull.analyze(analyzer);
867 subquerySubstitute = ifnull;
870 "a correlated subquery's select list: " + subquery.
toSql());
873 smap.put(subquery, subquerySubstitute);
874 return exprWithSubquery.substitute(smap, analyzer,
false);
static StatementBase rewrite(AnalysisResult analysisResult)
static final com.google.common.base.Predicate< Expr > NON_NULL_EMPTY_AGG
static Expr createJoinConjunct(Expr exprWithSubquery, InlineViewRef inlineView, Analyzer analyzer, boolean isCorrelated)
static Expr extractCorrelatedPredicates(Expr root, List< TupleId > tupleIds, ArrayList< Expr > matches)
static void updateInlineView(InlineViewRef inlineView, Expr expr, List< TupleId > parentQueryTids, List< Expr > lhsExprs, List< Expr > rhsExprs, boolean updateGroupBy)
SelectList getSelectList()
boolean isScalarSubquery()
static void rewriteUnionStatement(UnionStmt stmt, Analyzer analyzer)
static boolean mergeExpr(SelectStmt stmt, Expr expr, Analyzer analyzer)
static boolean hasSubqueryInDisjunction(Expr expr)
static BoolLiteral replaceExistsPredicate(ExistsPredicate predicate)
List< String > getPlanHints()
static final com.google.common.base.Predicate< Expr > IS_TRUE_LITERAL
static void replaceUnqualifiedStarItems(SelectStmt stmt, int tableIdx)
boolean hasGroupByClause()
static boolean canExtractCorrelatedPredicates(Expr expr, List< TupleId > subqueryTupleIds)
static void rewriteQueryStatement(QueryStmt stmt, Analyzer analyzer)
static Expr replaceBetweenPredicates(Expr expr)
static Expr rewriteExpr(Expr expr, Analyzer analyzer)
static boolean containsCorrelatedPredicate(Expr root, List< TupleId > tupleIds)
TupleDescriptor getDesc()
static void rewriteWhereClauseSubqueries(SelectStmt stmt, Analyzer analyzer)
static void rewriteSelectStatement(SelectStmt stmt, Analyzer analyzer)
NULL_AWARE_LEFT_ANTI_JOIN
static void canRewriteCorrelatedSubquery(Expr expr)
static final com.google.common.base.Predicate< Expr > IS_OR_PREDICATE
void setLimit(long limit)
static ArrayList< Expr > extractCorrelatedPredicates(SelectStmt subqueryStmt)
static final com.google.common.base.Predicate< Expr > IS_SCALAR_SUBQUERY
static boolean canEliminate(Expr expr)
boolean isBoundByTupleIds(List< TupleId > tids)
List< Expr > getConjuncts()
static boolean isCorrelatedPredicate(Expr expr, List< TupleId > tupleIds)
static final com.google.common.base.Predicate< Expr > IS_BUILTIN_AGG_FN