Exemplo n.º 1
0
 /** Populates baseTblSmap_ with our combined inline view smap and creates baseTblResultExprs. */
 protected void resolveInlineViewRefs(Analyzer analyzer) {
   // Gather the inline view substitution maps from the enclosed inline views
   for (TableRef tblRef : tableRefs_) {
     if (tblRef instanceof InlineViewRef) {
       InlineViewRef inlineViewRef = (InlineViewRef) tblRef;
       baseTblSmap_ = Expr.SubstitutionMap.combine(baseTblSmap_, inlineViewRef.getBaseTblSmap());
     }
   }
   baseTblResultExprs_ = Expr.cloneList(resultExprs_, baseTblSmap_);
   LOG.trace("baseTblSmap_: " + baseTblSmap_.debugString());
   LOG.trace("resultExprs: " + Expr.debugString(resultExprs_));
   LOG.trace("baseTblResultExprs: " + Expr.debugString(baseTblResultExprs_));
 }
Exemplo n.º 2
0
  /**
   * This select block might contain inline views. Substitute all exprs (result of the analysis) of
   * this select block referencing any of our inlined views, including everything registered with
   * the analyzer. Expressions created during parsing (such as whereClause) are not touched.
   */
  protected void substituteInlineViewExprs(Analyzer analyzer) {
    // Gather the inline view substitution maps from the enclosed inline views
    Expr.SubstitutionMap sMap = new Expr.SubstitutionMap();
    for (TableRef tblRef : tableRefs) {
      if (tblRef instanceof InlineViewRef) {
        InlineViewRef inlineViewRef = (InlineViewRef) tblRef;
        sMap = Expr.SubstitutionMap.combine(sMap, inlineViewRef.getExprSMap());
      }
    }

    // we might not have anything to substitute
    if (sMap.lhs.size() == 0) {
      return;
    }

    // Substitute select list, join clause, where clause, aggregate, order by
    // and this select block's analyzer expressions

    // select
    Expr.substituteList(resultExprs, sMap);

    // aggregation (group by and aggregation expr)
    if (aggInfo != null) {
      aggInfo.substitute(sMap);
    }

    // having
    if (havingPred != null) {
      havingPred.substitute(sMap);
    }

    // ordering
    if (sortInfo != null) {
      sortInfo.substitute(sMap);
    }

    // expressions registered inside the analyzer
    analyzer.substitute(sMap);
  }
Exemplo n.º 3
0
  /**
   * Analyze aggregation-relevant components of the select block (Group By clause, select list,
   * Order By clause), substitute AVG with SUM/COUNT, create the AggregationInfo, including the agg
   * output tuple, and transform all post-agg exprs given AggregationInfo's smap.
   *
   * @param analyzer
   * @throws AnalysisException
   */
  private void analyzeAggregation(Analyzer analyzer) throws AnalysisException, InternalException {
    if (groupingExprs == null
        && !selectList.isDistinct()
        && !Expr.contains(resultExprs, AggregateExpr.class)) {
      // we're not computing aggregates
      return;
    }

    // If we're computing an aggregate, we must have a FROM clause.
    if (tableRefs.size() == 0) {
      throw new AnalysisException("aggregation without a FROM clause is not allowed");
    }

    if ((groupingExprs != null || Expr.contains(resultExprs, AggregateExpr.class))
        && selectList.isDistinct()) {
      throw new AnalysisException(
          "cannot combine SELECT DISTINCT with aggregate functions or GROUP BY");
    }

    // disallow '*' and explicit GROUP BY (we can't group by '*', and if you need to
    // name all star-expanded cols in the group by clause you might as well do it
    // in the select list)
    if (groupingExprs != null) {
      for (SelectListItem item : selectList.getItems()) {
        if (item.isStar()) {
          throw new AnalysisException(
              "cannot combine '*' in select list with GROUP BY: " + item.toSql());
        }
      }
    }

    // analyze grouping exprs
    ArrayList<Expr> groupingExprsCopy = Lists.newArrayList();
    if (groupingExprs != null) {
      // make a deep copy here, we don't want to modify the original
      // exprs during analysis (in case we need to print them later)
      groupingExprsCopy = Expr.cloneList(groupingExprs, null);
      substituteOrdinals(groupingExprsCopy, "GROUP BY");
      Expr ambiguousAlias = getFirstAmbiguousAlias(groupingExprsCopy);
      if (ambiguousAlias != null) {
        throw new AnalysisException(
            "Column " + ambiguousAlias.toSql() + " in group by clause is ambiguous");
      }
      Expr.substituteList(groupingExprsCopy, aliasSMap);
      for (int i = 0; i < groupingExprsCopy.size(); ++i) {
        groupingExprsCopy.get(i).analyze(analyzer);
        if (groupingExprsCopy.get(i).contains(AggregateExpr.class)) {
          // reference the original expr in the error msg
          throw new AnalysisException(
              "GROUP BY expression must not contain aggregate functions: "
                  + groupingExprs.get(i).toSql());
        }
      }
    }

    // analyze having clause
    if (havingClause != null) {
      // substitute aliases in place (ordinals not allowed in having clause)
      havingPred = havingClause.clone(aliasSMap);
      havingPred.analyze(analyzer);
      havingPred.checkReturnsBool("HAVING clause", true);
      analyzer.registerConjuncts(havingPred, null, false);
    }

    List<Expr> orderingExprs = null;
    if (sortInfo != null) {
      orderingExprs = sortInfo.getOrderingExprs();
    }

    ArrayList<AggregateExpr> aggExprs = collectAggExprs();
    Expr.SubstitutionMap avgSMap = createAvgSMap(aggExprs, analyzer);

    // substitute AVG before constructing AggregateInfo
    Expr.substituteList(aggExprs, avgSMap);
    ArrayList<AggregateExpr> nonAvgAggExprs = Lists.newArrayList();
    Expr.collectList(aggExprs, AggregateExpr.class, nonAvgAggExprs);
    aggExprs = nonAvgAggExprs;
    createAggInfo(groupingExprsCopy, aggExprs, analyzer);

    // combine avg smap with the one that produces the final agg output
    AggregateInfo finalAggInfo =
        aggInfo.getSecondPhaseDistinctAggInfo() != null
            ? aggInfo.getSecondPhaseDistinctAggInfo()
            : aggInfo;
    Expr.SubstitutionMap combinedSMap =
        Expr.SubstitutionMap.combine(avgSMap, finalAggInfo.getSMap());
    LOG.debug("combined smap: " + combinedSMap.debugString());

    // change select list, having and ordering exprs to point to agg output
    Expr.substituteList(resultExprs, combinedSMap);
    LOG.debug("post-agg selectListExprs: " + Expr.debugString(resultExprs));
    if (havingPred != null) {
      havingPred = havingPred.substitute(combinedSMap);
      LOG.debug("post-agg havingPred: " + havingPred.debugString());
    }
    Expr.substituteList(orderingExprs, combinedSMap);
    LOG.debug("post-agg orderingExprs: " + Expr.debugString(orderingExprs));

    // check that all post-agg exprs point to agg output
    for (int i = 0; i < selectList.getItems().size(); ++i) {
      if (!resultExprs.get(i).isBound(finalAggInfo.getAggTupleId())) {
        throw new AnalysisException(
            "select list expression not produced by aggregation output "
                + "(missing from GROUP BY clause?): "
                + selectList.getItems().get(i).getExpr().toSql());
      }
    }
    if (orderByElements != null) {
      for (int i = 0; i < orderByElements.size(); ++i) {
        if (!orderingExprs.get(i).isBound(finalAggInfo.getAggTupleId())) {
          throw new AnalysisException(
              "ORDER BY expression not produced by aggregation output "
                  + "(missing from GROUP BY clause?): "
                  + orderByElements.get(i).getExpr().toSql());
        }
      }
    }
    if (havingPred != null) {
      if (!havingPred.isBound(finalAggInfo.getAggTupleId())) {
        throw new AnalysisException(
            "HAVING clause not produced by aggregation output "
                + "(missing from GROUP BY clause?): "
                + havingClause.toSql());
      }
    }
  }