15 package com.cloudera.impala.analysis;
17 import java.util.ArrayList;
18 import java.util.Collections;
19 import java.util.List;
22 import org.slf4j.Logger;
23 import org.slf4j.LoggerFactory;
34 import com.cloudera.impala.common.TreeNode;
35 import com.google.common.base.Preconditions;
36 import com.google.common.base.Predicates;
37 import com.google.common.collect.Iterables;
38 import com.google.common.collect.Lists;
39 import com.google.common.collect.Sets;
46 private final static Logger
LOG = LoggerFactory.getLogger(SelectStmt.class);
73 List<TableRef> tableRefList,
74 Expr wherePredicate, ArrayList<Expr> groupingExprs,
75 Expr havingPredicate, ArrayList<OrderByElement> orderByElements,
77 super(orderByElements, limitElement);
78 this.selectList_ = selectList;
79 if (tableRefList == null) {
80 this.tableRefs_ = Lists.newArrayList();
82 this.tableRefs_ = tableRefList;
84 this.whereClause_ = wherePredicate;
85 this.groupingExprs_ = groupingExprs;
86 this.havingClause_ = havingPredicate;
87 this.colLabels_ = Lists.newArrayList();
88 this.havingPred_ = null;
90 this.sortInfo_ = null;
92 for (
int i = 1; i < tableRefs_.size(); ++i) {
93 tableRefs_.get(i).setLeftTblRef(
tableRefs_.get(i - 1));
143 super.analyze(analyzer);
147 for (
int i = 0; i < tableRefs_.size(); ++i) {
149 TableRef tblRef = tableRefs_.get(i);
150 tblRef = analyzer.resolveTableRef(tblRef);
151 Preconditions.checkNotNull(tblRef);
152 tableRefs_.set(i, tblRef);
153 tblRef.setLeftTblRef(leftTblRef);
155 tblRef.analyze(analyzer);
158 if (analyzer.getMissingTbls().isEmpty())
throw e;
165 if (!analyzer.getMissingTbls().isEmpty()) {
170 selectList_.analyzePlanHints(analyzer);
173 for (
int i = 0; i < selectList_.getItems().size(); ++i) {
185 item.getExpr().
analyze(analyzer);
186 if (item.
getExpr().contains(Predicates.instanceOf(Subquery.class))) {
188 "Subqueries are not supported in the select list.");
190 resultExprs_.add(item.getExpr());
191 String label = item.toColumnLabel(i, analyzer.useHiveColLabels());
193 Expr existingAliasExpr = aliasSmap_.get(aliasRef);
194 if (existingAliasExpr != null && !existingAliasExpr.
equals(item.
getExpr())) {
197 ambiguousAliasList_.add(aliasRef);
199 aliasSmap_.put(aliasRef, item.getExpr().
clone());
200 colLabels_.add(label);
206 if (expr.getType().isComplexType()) {
208 "Expr '%s' in select list returns a complex type '%s'.\n" +
209 "Only scalar types are allowed in the select list.",
210 expr.toSql(), expr.getType().
toSql()));
214 if (TreeNode.contains(resultExprs_,
AnalyticExpr.class)) {
223 "cannot combine SELECT DISTINCT with analytic functions");
228 whereClause_.analyze(analyzer);
231 "aggregate function not allowed in WHERE clause");
233 whereClause_.checkReturnsBool(
"WHERE clause",
false);
234 Expr e = whereClause_.findFirstOf(AnalyticExpr.class);
237 "WHERE clause must not contain analytic expressions: " + e.toSql());
253 if (analyzer.hasEmptySpjResultSet() &&
aggInfo_ == null) {
254 analyzer.setHasEmptyResultSet();
259 graph.addDependencyPredicates(aggInfo_.getGroupingExprs());
264 graph.addDependencyPredicates(sortInfo_.getOrderingExprs());
267 if (
aggInfo_ != null) LOG.debug(
"post-analysis " + aggInfo_.debugString());
278 List<Expr> unassigned =
280 List<Expr> unassignedJoinConjuncts = Lists.newArrayList();
281 for (
Expr e: unassigned) {
282 if (analyzer.
evalByJoin(e)) unassignedJoinConjuncts.add(e);
284 List<Expr> baseTblJoinConjuncts =
285 Expr.substituteList(unassignedJoinConjuncts,
baseTblSmap_, analyzer,
false);
291 sortInfo_.materializeRequiredSlots(analyzer,
baseTblSmap_);
301 ArrayList<TupleId> tids = Lists.newArrayList();
303 List<Expr> conjuncts = analyzer.getUnassignedConjuncts(tids,
false);
305 analyticInfo_.materializeRequiredSlots(analyzer,
baseTblSmap_);
312 ArrayList<Expr> havingConjuncts = Lists.newArrayList();
316 Set<SlotId> groupBySlots = Sets.newHashSet();
317 for (
int i = 0; i < aggInfo_.getGroupingExprs().size(); ++i) {
318 groupBySlots.add(aggInfo_.getOutputTupleDesc().getSlots().get(i).getId());
322 ArrayList<Expr> bindingPredicates =
323 analyzer.getBoundPredicates(aggInfo_.getResultTupleId(), groupBySlots,
false);
324 havingConjuncts.addAll(bindingPredicates);
325 havingConjuncts.addAll(
326 analyzer.getUnassignedConjuncts(aggInfo_.getResultTupleId().asList(),
false));
328 aggInfo_.materializeRequiredSlots(analyzer,
baseTblSmap_);
341 InlineViewRef inlineViewRef = (InlineViewRef) tblRef;
343 ExprSubstitutionMap.combine(
baseTblSmap_, inlineViewRef.getBaseTblSmap());
348 LOG.trace(
"baseTblSmap_: " + baseTblSmap_.debugString());
349 LOG.trace(
"resultExprs: " + Expr.debugString(
resultExprs_));
354 List<TupleId> result = Lists.newArrayList();
356 result.add(ref.getId());
368 Path resolvedPath = null;
373 Preconditions.checkState(
false);
375 Preconditions.checkNotNull(resolvedPath);
384 throw new AnalysisException(
"'*' expression in select list requires FROM clause.");
388 if (analyzer.isSemiJoined(tableRef.getId()))
continue;
389 Path resolvedPath =
new Path(tableRef.getDesc(), Collections.<String>emptyList());
390 Preconditions.checkState(resolvedPath.resolve());
400 Preconditions.checkState(resolvedPath.isResolved());
401 if (resolvedPath.destTupleDesc() != null &&
402 resolvedPath.destTupleDesc().getTable() != null &&
403 resolvedPath.destTupleDesc().getPath().getMatchedTypes().isEmpty()) {
407 Table table = tupleDesc.getTable();
408 for (
Column c: table.getColumnsInHiveOrder()) {
414 Preconditions.checkState(resolvedPath.destType().isStructType());
416 Preconditions.checkNotNull(structType);
425 CollectionStructType cst = (CollectionStructType) structType;
455 Path p = Path.createRelPath(resolvedPath, relRawPath);
456 Preconditions.checkState(p.resolve());
459 slotRef.analyze(analyzer);
460 resultExprs_.add(slotRef);
461 colLabels_.add(relRawPath[relRawPath.length - 1]);
473 && !TreeNode.contains(
resultExprs_, Expr.isAggregatePredicate())
475 || !TreeNode.contains(sortInfo_.getOrderingExprs(),
484 "aggregation without a FROM clause is not allowed");
489 && selectList_.isDistinct()) {
491 "cannot combine SELECT DISTINCT with aggregate functions or GROUP BY");
501 "cannot combine '*' in select list with GROUP BY: " + item.toSql());
509 if (expr.contains(Predicates.instanceOf(
Subquery.class))) {
511 "Subqueries are not supported in the GROUP BY clause.");
517 ArrayList<Expr> groupingExprsCopy = Lists.newArrayList();
524 if (ambiguousAlias != null) {
526 "' in GROUP BY clause is ambiguous");
529 Expr.trySubstituteList(groupingExprsCopy,
aliasSmap_, analyzer,
false);
530 for (
int i = 0; i < groupingExprsCopy.size(); ++i) {
531 groupingExprsCopy.get(i).
analyze(analyzer);
532 if (groupingExprsCopy.get(i).contains(Expr.isAggregatePredicate())) {
535 "GROUP BY expression must not contain aggregate functions: "
538 if (groupingExprsCopy.get(i).contains(AnalyticExpr.class)) {
541 "GROUP BY expression must not contain analytic expressions: "
542 + groupingExprsCopy.get(i).toSql());
550 throw new AnalysisException(
"Subqueries are not supported in the HAVING clause.");
554 havingPred_.checkReturnsBool(
"HAVING clause",
true);
556 Expr analyticExpr = havingPred_.findFirstOf(AnalyticExpr.class);
557 if (analyticExpr != null) {
559 "HAVING clause must not contain analytic expressions: "
560 + analyticExpr.toSql());
566 ArrayList<FunctionCallExpr> aggExprs = Lists.newArrayList();
567 TreeNode.collect(
resultExprs_, Expr.isAggregatePredicate(), aggExprs);
569 havingPred_.collect(Expr.isAggregatePredicate(), aggExprs);
579 if (analyzer.getQueryCtx().getRequest().query_options.appx_count_distinct) {
582 if (!aggExpr.isDistinct()
583 || !aggExpr.getFnName().getFunction().equals(
"count")
584 || aggExpr.getParams().size() != 1) {
589 ndvFnCall.analyzeNoThrow(analyzer);
590 Preconditions.checkState(ndvFnCall.getType().equals(aggExpr.getType()));
591 ndvSmap.put(aggExpr, ndvFnCall);
594 List<Expr> substAggExprs = Expr.substituteList(aggExprs, ndvSmap, analyzer,
false);
596 for (
Expr aggExpr: substAggExprs) {
613 countAllMap = ExprSubstitutionMap.compose(ndvSmap, countAllMap, analyzer);
614 List<Expr> substitutedAggs =
615 Expr.substituteList(aggExprs, countAllMap, analyzer,
false);
617 TreeNode.collect(substitutedAggs, Expr.isAggregatePredicate(), aggExprs);
622 aggInfo_.getSecondPhaseDistinctAggInfo() != null
627 ExprSubstitutionMap.compose(countAllMap, finalAggInfo.getOutputSmap(), analyzer);
628 LOG.trace(
"combined smap: " + combinedSmap.debugString());
632 LOG.trace(
"desctbl: " + analyzer.getDescTbl().debugString());
633 LOG.trace(
"resultexprs: " + Expr.debugString(
resultExprs_));
634 resultExprs_ = Expr.substituteList(
resultExprs_, combinedSmap, analyzer,
false);
635 LOG.trace(
"post-agg selectListExprs: " + Expr.debugString(
resultExprs_));
639 Preconditions.checkState(!havingPred_.contains(
640 Predicates.instanceOf(Subquery.class)));
641 havingPred_ = havingPred_.substitute(combinedSmap, analyzer,
false);
643 LOG.debug(
"post-agg havingPred: " + havingPred_.debugString());
646 sortInfo_.substituteOrderingExprs(combinedSmap, analyzer);
647 LOG.debug(
"post-agg orderingExprs: " +
648 Expr.debugString(sortInfo_.getOrderingExprs()));
652 for (
int i = 0; i < selectList_.getItems().size(); ++i) {
653 if (!resultExprs_.get(i).isBound(finalAggInfo.getOutputTupleId())) {
655 "select list expression not produced by aggregation output "
656 +
"(missing from GROUP BY clause?): "
661 for (
int i = 0; i < orderByElements_.size(); ++i) {
665 "ORDER BY expression not produced by aggregation output "
666 +
"(missing from GROUP BY clause?): "
674 "HAVING clause not produced by aggregation output "
675 +
"(missing from GROUP BY clause?): "
690 List<FunctionCallExpr> aggExprs,
Analyzer analyzer)
696 return scalarCountAllMap;
702 return !expr.isDistinct();
705 if (Iterables.all(aggExprs, isNotDistinctPred)) {
707 return scalarCountAllMap;
713 return expr.getFnName().getFunction().equals(
"count");
718 Iterables.filter(aggExprs, Predicates.and(isCountPred, isNotDistinctPred));
721 ArrayList<Expr> zeroIfNullParam = Lists.newArrayList(countAllAgg.clone());
724 zeroIfNull.analyze(analyzer);
725 scalarCountAllMap.put(countAllAgg, zeroIfNull);
728 return scalarCountAllMap;
735 ArrayList<FunctionCallExpr> aggExprs,
Analyzer analyzer)
741 Preconditions.checkState(groupingExprs.isEmpty());
742 Preconditions.checkState(aggExprs.isEmpty());
743 ArrayList<Expr> distinctGroupingExprs = Expr.cloneList(
resultExprs_);
745 AggregateInfo.create(distinctGroupingExprs, null, null, analyzer);
747 aggInfo_ = AggregateInfo.create(groupingExprs, aggExprs, null, analyzer);
758 ArrayList<Expr> analyticExprs = Lists.newArrayList();
759 TreeNode.collect(
resultExprs_, AnalyticExpr.class, analyticExprs);
761 TreeNode.collect(sortInfo_.getOrderingExprs(),
AnalyticExpr.class,
764 if (analyticExprs.isEmpty())
return;
765 analyticInfo_ = AnalyticInfo.create(analyticExprs, analyzer);
769 resultExprs_ = Expr.substituteList(
resultExprs_, analyticInfo_.getSmap(), analyzer,
771 LOG.trace(
"post-analytic selectListExprs: " + Expr.debugString(
resultExprs_));
773 sortInfo_.substituteOrderingExprs(analyticInfo_.getSmap(), analyzer);
774 LOG.trace(
"post-analytic orderingExprs: " +
775 Expr.debugString(sortInfo_.getOrderingExprs()));
787 StringBuilder strBuilder =
new StringBuilder();
789 strBuilder.append(withClause_.toSql());
790 strBuilder.append(
" ");
794 strBuilder.append(
"SELECT ");
796 strBuilder.append(
"DISTINCT ");
799 strBuilder.append(ToSqlUtils.getPlanHintsSql(selectList_.getPlanHints()) +
" ");
801 for (
int i = 0; i < selectList_.getItems().size(); ++i) {
802 strBuilder.append(selectList_.getItems().
get(i).toSql());
803 strBuilder.append((i+1 != selectList_.getItems().size()) ?
", " :
"");
807 strBuilder.append(
" FROM ");
808 for (
int i = 0; i < tableRefs_.size(); ++i) {
809 strBuilder.append(tableRefs_.get(i).
toSql());
814 strBuilder.append(
" WHERE ");
815 strBuilder.append(whereClause_.toSql());
819 strBuilder.append(
" GROUP BY ");
820 for (
int i = 0; i < groupingExprs_.size(); ++i) {
821 strBuilder.append(groupingExprs_.get(i).
toSql());
822 strBuilder.append((i+1 != groupingExprs_.size()) ?
", " :
"");
827 strBuilder.append(
" HAVING ");
828 strBuilder.append(havingClause_.toSql());
832 strBuilder.append(
" ORDER BY ");
833 for (
int i = 0; i < orderByElements_.size(); ++i) {
834 strBuilder.append(orderByElements_.get(i).
toSql());
835 strBuilder.append((i+1 != orderByElements_.size()) ?
", " :
"");
839 strBuilder.append(limitElement_.toSql());
840 return strBuilder.toString();
853 tupleIdList.add(sortInfo_.getSortTupleDescriptor().getId());
856 tupleIdList.add(aggInfo_.getResultTupleId());
861 if (tblRef.getJoinOp().isLeftSemiJoin())
continue;
864 if (tblRef.getJoinOp().isRightSemiJoin()) tupleIdList.clear();
865 tupleIdList.addAll(tblRef.getMaterializedTupleIds());
870 tupleIdList.add(analyticInfo_.getOutputTupleId());
875 ArrayList<TableRef>
clone = Lists.newArrayList();
877 clone.add(tblRef.clone());
void substituteOrdinals(List< Expr > exprs, String errorPrefix, Analyzer analyzer)
ArrayList< String > getColLabels()
ArrayList< Expr > groupingExprs_
List< TableRef > getTableRefs()
void resolveInlineViewRefs(Analyzer analyzer)
void analyze(Analyzer analyzer)
AggregateInfo getSecondPhaseDistinctAggInfo()
void getMaterializedTupleIds(ArrayList< TupleId > tupleIdList)
ColumnAliasGenerator columnAliasGenerator_
void setWhereClause(Expr whereClause)
static com.google.common.base.Predicate< Expr > isAggregatePredicate()
StructField getOptionalField()
TableAliasGenerator tableAliasGenerator_
ArrayList< OrderByElement > cloneOrderByElements()
SelectList getSelectList()
ArrayList< Expr > resultExprs_
ArrayList< TableRef > cloneTableRefs()
void analyzeAggregation(Analyzer analyzer)
boolean returnsSingleRow()
SelectStmt(SelectList selectList, List< TableRef > tableRefList, Expr wherePredicate, ArrayList< Expr > groupingExprs, Expr havingPredicate, ArrayList< OrderByElement > orderByElements, LimitElement limitElement)
TableAliasGenerator getTableAliasGenerator()
void expandStar(Analyzer analyzer)
LimitElement limitElement_
TupleId getOutputTupleId()
void createSortTupleInfo(Analyzer analyzer)
boolean evalByJoin(Expr e)
void materializeRequiredSlots(Analyzer analyzer)
ColumnAliasGenerator getColumnAliasGenerator()
ArrayList< FunctionCallExpr > getAggregateExprs()
void expandStar(Path resolvedPath, Analyzer analyzer)
List< String > getRawPath()
boolean hasGroupByClause()
final ExprSubstitutionMap aliasSmap_
Expr getFirstAmbiguousAlias(List< Expr > exprs)
final ArrayList< String > colLabels_
ArrayList< Expr > baseTblResultExprs_
AnalyticInfo getAnalyticInfo()
AnalyticInfo analyticInfo_
AggregateInfo getAggInfo()
Path analyzeStarPath(List< String > rawPath, Analyzer analyzer)
void materializeSlots(Analyzer analyzer, List< Expr > exprs)
final List< TableRef > tableRefs_
void addStarResultExpr(Path resolvedPath, Analyzer analyzer, String...relRawPath)
ExprSubstitutionMap createCountAllMap(List< FunctionCallExpr > aggExprs, Analyzer analyzer)
ArrayList< OrderByElement > orderByElements_
static final String MAP_VALUE_FIELD_NAME
boolean equals(Object obj)
WithClause cloneWithClause()
void createAggInfo(ArrayList< Expr > groupingExprs, ArrayList< FunctionCallExpr > aggExprs, Analyzer analyzer)
boolean hasAnalyticInfo()
void analyzeAnalytics(Analyzer analyzer)
List< TupleId > getTableRefIds()
void createSortInfo(Analyzer analyzer)
static final String ARRAY_ITEM_FIELD_NAME
List< SelectListItem > getItems()
List< Expr > getOrderingExprs()
ExprSubstitutionMap baseTblSmap_
boolean isBound(TupleId tid)
ExprSubstitutionMap getBaseTblSmap()
static final String MAP_KEY_FIELD_NAME