QueryStmt.java
// 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.
// This file is copied from
// https://github.com/apache/impala/blob/branch-2.9.0/fe/src/main/java/org/apache/impala/QueryStmt.java
// and modified by Doris
package org.apache.doris.analysis;
import org.apache.doris.catalog.TableIf;
import org.apache.doris.catalog.Type;
import org.apache.doris.common.AnalysisException;
import org.apache.doris.common.ErrorCode;
import org.apache.doris.common.ErrorReport;
import org.apache.doris.common.UserException;
import org.apache.doris.qe.ConnectContext;
import org.apache.doris.rewrite.ExprRewriter;
import org.apache.doris.rewrite.mvrewrite.CountDistinctToBitmapOrHLLRule;
import org.apache.doris.thrift.TQueryOptions;
import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
/**
* Abstract base class for any statement that returns results
* via a list of result expressions, for example a
* SelectStmt or UnionStmt. Also maintains a map of expression substitutions
* for replacing expressions from ORDER BY or GROUP BY clauses with
* their corresponding result expressions.
* Used for sharing members/methods and some of the analysis code, in particular the
* analysis of the ORDER BY and LIMIT clauses.
*/
@Deprecated
public abstract class QueryStmt extends StatementBase implements Queriable, NotFallbackInParser {
private static final Logger LOG = LogManager.getLogger(QueryStmt.class);
/////////////////////////////////////////
// BEGIN: Members that need to be reset()
protected WithClause withClause;
protected ArrayList<OrderByElement> orderByElements;
// Limit element could not be null, the default limit element is NO_LIMIT
protected LimitElement limitElement;
// This is a internal element which is used to query plan.
// It will not change the origin stmt and present in toSql.
protected AssertNumRowsElement assertNumRowsElement;
/**
* For a select statment:
* List of executable exprs in select clause (star-expanded, ordinals and
* aliases substituted, agg output substituted
* For a union statement:
* List of slotrefs into the tuple materialized by the union.
*/
protected ArrayList<Expr> resultExprs = Lists.newArrayList();
// For a select statement: select list exprs resolved to base tbl refs
// For a union statement: same as resultExprs
/**
* For inline view, Doris will generate an extra layer of tuple (virtual) during semantic analysis.
* But if the expr in the outer select stmt involves columns in the inline view,
* it can only be mapped to this layer of tuple (virtual) at the beginning (@resultExprs).
* If you want to really associate with the column in the inlineview,
* you need to substitute it with baseTblSmap to get the correct expr (@baseTblResultExprs).
* resultExprs + baseTblSmap = baseTblResultExprs
* For example:
* select c1 from (select k1 c1 from table group by k1) tmp;
* tuple 0: table, tuple1: group by tuple2: tmp
* resultExprs: c1 belongs to tuple2(tmp)
* baseTblResultExprs: c1 belongs to tuple1(group by)
*/
protected ArrayList<Expr> baseTblResultExprs = Lists.newArrayList();
/**
* Map of expression substitutions for replacing aliases
* in "order by" or "group by" clauses with their corresponding result expr.
*/
protected final ExprSubstitutionMap aliasSMap;
protected final ExprSubstitutionMap mvSMap;
/**
* Select list item alias does not have to be unique.
* This list contains all the non-unique aliases. For example,
* select int_col a, string_col a from alltypessmall;
* Both columns are using the same alias "a".
*/
protected final ArrayList<Expr> ambiguousAliasList;
protected SortInfo sortInfo;
// evaluateOrderBy_ is true if there is an order by clause that must be evaluated.
// False for nested query stmts with an order-by clause without offset/limit.
// sortInfo_ is still generated and used in analysis to ensure that the order-by clause
// is well-formed.
protected boolean evaluateOrderBy;
protected boolean needToSql = false;
// used by hll
protected boolean fromInsert = false;
// order by elements which has been analyzed
// For example: select k1 a from t order by a;
// this parameter: order by t.k1
protected List<OrderByElement> orderByElementsAfterAnalyzed;
/////////////////////////////////////////
// END: Members that need to be reset()
// represent the "INTO OUTFILE" clause
protected OutFileClause outFileClause;
/**
* If the query stmt belongs to CreateMaterializedViewStmt,
* such as
* `CREATE MATERIALIZED VIEW mv AS SELECT bitmap_union(to_bitmap(k1)) from table`
* query stmt will not be rewrite by MVRewriter.
* The `bitmap_union(to_bitmap(k1))` is the definition of the mv column rather then a expr.
* So `forbiddenMVRewrite` will be set to true to protect the definition of the mv column from being overwritten.
* <p>
* In other query case, `forbiddenMVRewrite` is always false.
*/
private boolean forbiddenMVRewrite = false;
/**
* If the tuple id in `disableMVRewriteTupleIds`, the expr which belongs to this tuple will not be MVRewritten.
* Initially this set is an empty set.
* When the scan node is unable to match any index in selecting the materialized view,
* the tuple is added to this set.
* The query will be re-executed, and this tuple will not be mv rewritten.
* For example:
* TableA: (k1 int, k2 int, k3 int)
* MV: (k1 int, mv_bitmap_union_k2 bitmap bitmap_union)
* Query: select k3, bitmap_union(to_bitmap(k2)) from TableA
* First analyze: MV rewriter enable and this set is empty
* select k3, bitmap_union(mv_bitmap_union_k2) from TableA
* SingleNodePlanner: could not select any index for TableA
* Add table to disableMVRewriteTupleIds.
* `disableMVRewriteTupleIds` = {TableA}
* Re-executed:
* Second analyze: MV rewrite disable in table and use origin stmt.
* select k3, bitmap_union(to_bitmap(k2)) from TableA
* SingleNodePlanner: base index selected
*/
private Set<TupleId> disableTuplesMVRewriter = Sets.newHashSet();
protected boolean toSQLWithSelectList;
protected boolean isPointQuery;
protected boolean toSQLWithHint;
QueryStmt(ArrayList<OrderByElement> orderByElements, LimitElement limitElement) {
this.orderByElements = orderByElements;
this.limitElement = limitElement;
this.aliasSMap = new ExprSubstitutionMap();
this.mvSMap = new ExprSubstitutionMap();
this.ambiguousAliasList = Lists.newArrayList();
this.sortInfo = null;
}
@Override
public void analyze(Analyzer analyzer) throws AnalysisException, UserException {
if (isAnalyzed()) {
return;
}
super.analyze(analyzer);
analyzeLimit(analyzer);
if (hasWithClause()) {
withClause.analyze(analyzer);
}
}
private void analyzeLimit(Analyzer analyzer) throws AnalysisException {
limitElement.analyze(analyzer);
}
/**
* Returns a list containing all the materialized tuple ids that this stmt is
* correlated with (i.e., those tuple ids from outer query blocks that TableRefs
* inside this stmt are rooted at).
*
* Throws if this stmt contains an illegal mix of un/correlated table refs.
* A statement is illegal if it contains a TableRef correlated with a parent query
* block as well as a table ref with an absolute path (e.g. a BaseTabeRef). Such a
* statement would generate a Subplan containing a base table scan (very expensive),
* and should therefore be avoided.
*
* In other words, the following cases are legal:
* (1) only uncorrelated table refs
* (2) only correlated table refs
* (3) a mix of correlated table refs and table refs rooted at those refs
* (the statement is 'self-contained' with respect to correlation)
*/
public List<TupleId> getCorrelatedTupleIds(Analyzer analyzer) throws AnalysisException {
// Correlated tuple ids of this stmt.
List<TupleId> correlatedTupleIds = Lists.newArrayList();
// First correlated and absolute table refs. Used for error detection/reporting.
// We pick the first ones for simplicity. Choosing arbitrary ones is equally valid.
TableRef correlatedRef = null;
TableRef absoluteRef = null;
// Materialized tuple ids of the table refs checked so far.
Set<TupleId> tblRefIds = Sets.newHashSet();
List<TableRef> tblRefs = Lists.newArrayList();
collectTableRefs(tblRefs);
for (TableRef tblRef : tblRefs) {
if (absoluteRef == null && !tblRef.isRelative()) {
absoluteRef = tblRef;
}
/*if (tblRef.isCorrelated()) {
*
* // Check if the correlated table ref is rooted at a tuple descriptor from within
* // this query stmt. If so, the correlation is contained within this stmt
* // and the table ref does not conflict with absolute refs.
* CollectionTableRef t = (CollectionTableRef) tblRef;
* Preconditions.checkState(t.getResolvedPath().isRootedAtTuple());
* // This check relies on tblRefs being in depth-first order.
* if (!tblRefIds.contains(t.getResolvedPath().getRootDesc().getId())) {
* if (correlatedRef == null) correlatedRef = tblRef;
* correlatedTupleIds.add(t.getResolvedPath().getRootDesc().getId());
* }
*
}*/
if (correlatedRef != null && absoluteRef != null) {
throw new AnalysisException(String.format(
"Nested query is illegal because it contains a table reference '%s' "
+ "correlated with an outer block as well as an uncorrelated one '%s':\n%s",
correlatedRef.tableRefToSql(), absoluteRef.tableRefToSql(), toSql()));
}
tblRefIds.add(tblRef.getId());
}
return correlatedTupleIds;
}
public boolean isEvaluateOrderBy() {
return evaluateOrderBy;
}
public ArrayList<Expr> getBaseTblResultExprs() {
return baseTblResultExprs;
}
public void setNeedToSql(boolean needToSql) {
this.needToSql = needToSql;
}
public boolean isDisableTuplesMVRewriter(Expr expr) {
if (disableTuplesMVRewriter.isEmpty()) {
return false;
}
return expr.isBoundByTupleIds(disableTuplesMVRewriter.stream().collect(Collectors.toList()));
}
protected Expr rewriteQueryExprByMvColumnExpr(Expr expr, Analyzer analyzer) throws AnalysisException {
if (analyzer == null || analyzer.getMVExprRewriter() == null) {
return expr;
}
ExprRewriter rewriter;
if (forbiddenMVRewrite) {
rewriter = new ExprRewriter(Lists.newArrayList(CountDistinctToBitmapOrHLLRule.INSTANCE),
Lists.newArrayList());
} else {
rewriter = analyzer.getMVExprRewriter();
rewriter.reset();
rewriter.setInfoMVRewriter(disableTuplesMVRewriter, mvSMap, aliasSMap);
}
rewriter.setUpBottom();
Expr result = rewriter.rewrite(expr, analyzer);
return result;
}
/**
* Creates sortInfo by resolving aliases and ordinals in the orderingExprs.
* If the query stmt is an inline view/union operand, then order-by with no
* limit with offset is not allowed, since that requires a sort and merging-exchange,
* and subsequent query execution would occur on a single machine.
* Sets evaluateOrderBy_ to false for ignored order-by w/o limit/offset in nested
* queries.
*/
protected void createSortInfo(Analyzer analyzer) throws AnalysisException {
// not computing order by
if (orderByElements == null) {
evaluateOrderBy = false;
return;
}
ArrayList<Expr> orderingExprs = Lists.newArrayList();
ArrayList<Boolean> isAscOrder = Lists.newArrayList();
ArrayList<Boolean> nullsFirstParams = Lists.newArrayList();
// extract exprs
for (OrderByElement orderByElement : orderByElements) {
// create copies, we don't want to modify the original parse node, in case
// we need to print it
orderingExprs.add(orderByElement.getExpr().clone());
isAscOrder.add(Boolean.valueOf(orderByElement.getIsAsc()));
nullsFirstParams.add(orderByElement.getNullsFirstParam());
}
substituteOrdinalsAliases(orderingExprs, "ORDER BY", analyzer, true);
// save the order by element after analyzed
orderByElementsAfterAnalyzed = Lists.newArrayList();
for (int i = 0; i < orderByElements.size(); i++) {
// equal count distinct
orderingExprs.set(i, rewriteQueryExprByMvColumnExpr(orderingExprs.get(i), analyzer));
OrderByElement orderByElement = new OrderByElement(orderingExprs.get(i), isAscOrder.get(i),
nullsFirstParams.get(i));
orderByElementsAfterAnalyzed.add(orderByElement);
}
if (!analyzer.isRootAnalyzer() && hasOffset() && !hasLimit()) {
throw new AnalysisException("Order-by with offset without limit not supported"
+ " in nested queries.");
}
for (Expr expr : orderingExprs) {
if (expr.getType().isOnlyMetricType()) {
throw new AnalysisException(Type.OnlyMetricTypeErrorMsg);
}
}
sortInfo = new SortInfo(orderingExprs, isAscOrder, nullsFirstParams);
// order by w/o limit and offset in inline views, set operands and insert statements
// are ignored.
if (!hasLimit() && !hasOffset() && (!analyzer.isRootAnalyzer() || fromInsert)) {
evaluateOrderBy = false;
if (LOG.isDebugEnabled()) {
// Return a warning that the order by was ignored.
StringBuilder strBuilder = new StringBuilder();
strBuilder.append("Ignoring ORDER BY clause without LIMIT or OFFSET: ");
strBuilder.append("ORDER BY ");
strBuilder.append(orderByElements.get(0).toSql());
for (int i = 1; i < orderByElements.size(); ++i) {
strBuilder.append(", ").append(orderByElements.get(i).toSql());
}
strBuilder.append(".\nAn ORDER BY appearing in a view, subquery, union operand, ");
strBuilder.append("or an insert/ctas statement has no effect on the query result ");
strBuilder.append("unless a LIMIT and/or OFFSET is used in conjunction ");
strBuilder.append("with the ORDER BY.");
if (LOG.isDebugEnabled()) {
LOG.debug(strBuilder.toString());
}
}
} else {
evaluateOrderBy = true;
}
}
/**
* Create a tuple descriptor for the single tuple that is materialized, sorted and
* output by the exec node implementing the sort. Done by materializing slot refs in
* the order-by and result expressions. Those SlotRefs in the ordering and result exprs
* are substituted with SlotRefs into the new tuple. This simplifies sorting logic for
* total (no limit) sorts.
* Done after analyzeAggregation() since ordering and result exprs may refer to the
* outputs of aggregation.
*/
protected void createSortTupleInfo(Analyzer analyzer) throws AnalysisException {
Preconditions.checkState(evaluateOrderBy);
for (Expr orderingExpr : sortInfo.getOrderingExprs()) {
if (orderingExpr.getType().isComplexType()) {
throw new AnalysisException(String.format(
"ORDER BY expression '%s' with "
+ "complex type '%s' is not supported.",
orderingExpr.toSql(), orderingExpr.getType().toSql()));
}
}
ExprSubstitutionMap smap = sortInfo.createSortTupleInfo(resultExprs, analyzer);
for (int i = 0; i < smap.size(); ++i) {
if (!(smap.getLhs().get(i) instanceof SlotRef)
|| !(smap.getRhs().get(i) instanceof SlotRef)) {
continue;
}
// TODO(zc)
// SlotRef inputSlotRef = (SlotRef) smap.getLhs().get(i);
// SlotRef outputSlotRef = (SlotRef) smap.getRhs().get(i);
// if (hasLimit()) {
// analyzer.registerValueTransfer(
// inputSlotRef.getSlotId(), outputSlotRef.getSlotId());
// } else {
// analyzer.createAuxEquivPredicate(outputSlotRef, inputSlotRef);
// }
}
substituteResultExprs(smap, analyzer);
}
/**
* Return the first expr in exprs that is a non-unique alias. Return null if none of
* exprs is an ambiguous alias.
*/
protected Expr getFirstAmbiguousAlias(List<Expr> exprs) {
for (Expr exp : exprs) {
if (ambiguousAliasList.contains(exp)) {
return exp;
}
}
return null;
}
protected Expr getFirstAmbiguousAlias(Expr expr) {
return expr.findEqual(ambiguousAliasList);
}
/**
* Substitute exprs of the form "<number>" with the corresponding
* expressions and any alias references in aliasSmap_.
* Modifies exprs list in-place.
*/
protected void substituteOrdinalsAliases(List<Expr> exprs, String errorPrefix,
Analyzer analyzer, boolean aliasFirst) throws AnalysisException {
Expr ambiguousAlias = getFirstAmbiguousAlias(exprs);
if (ambiguousAlias != null) {
ErrorReport.reportAnalysisException(ErrorCode.ERR_NON_UNIQ_ERROR, ambiguousAlias.toColumnLabel());
}
ListIterator<Expr> i = exprs.listIterator();
while (i.hasNext()) {
Expr expr = i.next();
// We can substitute either by ordinal or by alias.
// If we substitute by ordinal, we should not replace any aliases, since
// the new expression was copied from the select clause context, where
// alias substitution is not performed in the same way.
Expr substituteExpr = trySubstituteOrdinal(expr, errorPrefix, analyzer);
if (substituteExpr == null) {
if (aliasFirst) {
substituteExpr = expr.trySubstitute(aliasSMap, analyzer, false);
} else {
try {
// use col name from tableRefs first
substituteExpr = expr.clone();
substituteExpr.analyze(analyzer);
} catch (AnalysisException ex) {
if (ConnectContext.get() != null) {
ConnectContext.get().getState().reset();
}
// then consider alias name
substituteExpr = expr.trySubstitute(aliasSMap, analyzer, false);
}
}
}
i.set(substituteExpr);
}
}
// Attempt to replace an expression of form "<number>" with the corresponding
// select list items. Return null if not an ordinal expression.
private Expr trySubstituteOrdinal(Expr expr, String errorPrefix,
Analyzer analyzer) throws AnalysisException {
if (!(expr instanceof IntLiteral)) {
return null;
}
expr.analyze(analyzer);
if (!expr.getType().isIntegerType()) {
return null;
}
long pos = ((IntLiteral) expr).getLongValue();
if (pos < 1) {
throw new AnalysisException(
errorPrefix + ": ordinal must be >= 1: " + expr.toSql());
}
if (pos > resultExprs.size()) {
throw new AnalysisException(
errorPrefix + ": ordinal exceeds number of items in select list: " + expr.toSql());
}
// Create copy to protect against accidentally shared state.
return resultExprs.get((int) pos - 1).clone();
}
public void getWithClauseTables(Analyzer analyzer, boolean expandView, Map<Long, TableIf> tableMap,
Set<String> parentViewNameSet) throws AnalysisException {
if (withClause != null) {
withClause.getTables(analyzer, expandView, tableMap, parentViewNameSet);
}
}
public void getWithClauseTableRefs(Analyzer analyzer, List<TableRef> tblRefs, Set<String> parentViewNameSet) {
if (withClause != null) {
withClause.getTableRefs(analyzer, tblRefs, parentViewNameSet);
}
}
/**
* collect all exprs of a QueryStmt to a map
* @param exprMap
*/
public void collectExprs(Map<String, Expr> exprMap) {
}
/**
* put all rewritten exprs back to the ori QueryStmt
* @param rewrittenExprMap
*/
public void putBackExprs(Map<String, Expr> rewrittenExprMap) {
}
@Override
public void foldConstant(ExprRewriter rewriter, TQueryOptions tQueryOptions) throws AnalysisException {
Preconditions.checkState(isAnalyzed());
Map<String, Expr> exprMap = new HashMap<>();
collectExprs(exprMap);
rewriter.rewriteConstant(exprMap, analyzer, tQueryOptions);
if (rewriter.changed()) {
putBackExprs(exprMap);
}
}
@Override
public void rewriteElementAtToSlot(ExprRewriter rewriter, TQueryOptions tQueryOptions) throws AnalysisException {
}
/**
* register expr_id of expr and its children, if not set
* @param expr
*/
public void registerExprId(Expr expr) {
if (expr.getId() == null) {
analyzer.registerExprId(expr);
}
for (Expr child : expr.getChildren()) {
registerExprId(child);
}
}
/**
* check whether expr and it's children contain alias
* @param expr expr to be checked
* @return true if contains, otherwise false
*/
public boolean containAlias(Expr expr) {
for (Expr child : expr.getChildren()) {
if (containAlias(child)) {
return true;
}
}
if (null != aliasSMap.get(expr)) {
return true;
}
return false;
}
public Expr getExprFromAliasSMapDirect(Expr expr) throws AnalysisException {
return expr.trySubstitute(aliasSMap, analyzer, false);
}
public Expr getExprFromAliasSMap(Expr expr) {
return expr;
}
// get tables used by this query.
// Set<String> parentViewNameSet contain parent stmt view name
// to make sure query like "with tmp as (select * from db1.table1) " +
// "select a.siteid, b.citycode, a.siteid from (select siteid, citycode from tmp) a " +
// "left join (select siteid, citycode from tmp) b on a.siteid = b.siteid;";
// tmp in child stmt "(select siteid, citycode from tmp)" do not contain with_Clause
// so need to check is view name by parentViewNameSet.
// issue link: https://github.com/apache/doris/issues/4598
public abstract void getTables(Analyzer analyzer, boolean expandView, Map<Long, TableIf> tables,
Set<String> parentViewNameSet) throws AnalysisException;
// get TableRefs in this query, including physical TableRefs of this statement and
// nested statements of inline views and with_Clause.
public abstract void getTableRefs(Analyzer analyzer, List<TableRef> tblRefs, Set<String> parentViewNameSet);
/**
* UnionStmt and SelectStmt have different implementations.
*/
public abstract ArrayList<String> getColLabels();
public abstract ArrayList<List<String>> getSubColPath();
/**
* Returns the materialized tuple ids of the output of this stmt.
* Used in case this stmt is part of an @InlineViewRef,
* since we need to know the materialized tupls ids of a TableRef.
*/
public abstract void getMaterializedTupleIds(ArrayList<TupleId> tupleIdList);
/**
* Returns all physical (non-inline-view) TableRefs of this statement and the nested
* statements of inline views. The returned TableRefs are in depth-first order.
*/
public abstract void collectTableRefs(List<TableRef> tblRefs);
abstract List<TupleId> collectTupleIds();
public ArrayList<OrderByElement> getOrderByElements() {
return orderByElements;
}
public List<OrderByElement> getOrderByElementsAfterAnalyzed() {
return orderByElementsAfterAnalyzed;
}
public void removeOrderByElements() {
orderByElements = null;
}
public void setWithClause(WithClause withClause) {
this.withClause = withClause;
}
public boolean hasWithClause() {
return withClause != null;
}
public WithClause getWithClause() {
return withClause;
}
public boolean hasOrderByClause() {
return orderByElements != null;
}
public boolean hasLimit() {
return limitElement != null && limitElement.hasLimit();
}
public boolean hasOffset() {
return limitElement != null && limitElement.hasOffset();
}
public long getLimit() {
return limitElement.getLimit();
}
public void setLimit(long limit) {
Preconditions.checkState(limit >= 0);
long newLimit = hasLimitClause() ? Math.min(limit, getLimit()) : limit;
long offset = hasLimitClause() ? getOffset() : 0;
limitElement = new LimitElement(offset, newLimit);
}
public void removeLimitElement() {
limitElement = LimitElement.NO_LIMIT;
}
public long getOffset() {
return limitElement.getOffset();
}
public void setAssertNumRowsElement(int desiredNumOfRows, AssertNumRowsElement.Assertion assertion) {
this.assertNumRowsElement = new AssertNumRowsElement(desiredNumOfRows, toSql(), assertion);
}
public AssertNumRowsElement getAssertNumRowsElement() {
return assertNumRowsElement;
}
public void setIsExplain(ExplainOptions options) {
this.explainOptions = options;
}
public boolean isExplain() {
return this.explainOptions != null;
}
public boolean hasLimitClause() {
return limitElement.hasLimit();
}
public SortInfo getSortInfo() {
return sortInfo;
}
public boolean evaluateOrderBy() {
return evaluateOrderBy;
}
public ArrayList<Expr> getResultExprs() {
return resultExprs;
}
/**
* Substitutes the result expressions with smap. Preserves the original types of
* those expressions during the substitution.
*/
public void substituteResultExprs(ExprSubstitutionMap smap, Analyzer analyzer) {
resultExprs = Expr.substituteList(resultExprs, smap, analyzer, true);
}
public boolean isForbiddenMVRewrite() {
return forbiddenMVRewrite;
}
public void forbiddenMVRewrite() {
this.forbiddenMVRewrite = true;
}
public void updateDisableTuplesMVRewriter(TupleId tupleId) {
disableTuplesMVRewriter.add(tupleId);
}
public void updateDisableTuplesMVRewriter(Set<TupleId> tupleIds) {
disableTuplesMVRewriter.addAll(tupleIds);
}
public Set<TupleId> getDisableTuplesMVRewriter() {
return disableTuplesMVRewriter;
}
/**
* Mark all slots that need to be materialized for the execution of this stmt.
* This excludes slots referenced in resultExprs (it depends on the consumer of
* the output of the stmt whether they'll be accessed) and single-table predicates
* (the PlanNode that materializes that tuple can decide whether evaluating those
* predicates requires slot materialization).
* This is called prior to plan tree generation and allows tuple-materializing
* PlanNodes to compute their tuple's mem layout.
*/
public abstract void materializeRequiredSlots(Analyzer analyzer) throws AnalysisException;
/**
* Mark slots referenced in exprs as materialized.
*/
protected void materializeSlots(Analyzer analyzer, List<Expr> exprs) {
List<SlotId> slotIds = Lists.newArrayList();
for (Expr e : exprs) {
e.getIds(null, slotIds);
}
analyzer.getDescTbl().markSlotsMaterialized(slotIds);
}
@Override
public RedirectStatus getRedirectStatus() {
return RedirectStatus.NO_FORWARD;
}
public ArrayList<OrderByElement> cloneOrderByElements() {
if (orderByElements == null) {
return null;
}
ArrayList<OrderByElement> result =
Lists.newArrayListWithCapacity(orderByElements.size());
for (OrderByElement o : orderByElements) {
result.add(o.clone());
}
return result;
}
public WithClause cloneWithClause() {
return withClause != null ? withClause.clone() : null;
}
public OutFileClause cloneOutfileCluse() {
return outFileClause != null ? outFileClause.clone() : null;
}
public String toDigest() {
return "";
}
/**
* C'tor for cloning.
*/
protected QueryStmt(QueryStmt other) {
super(other);
withClause = other.cloneWithClause();
outFileClause = other.cloneOutfileCluse();
orderByElements = other.cloneOrderByElements();
limitElement = other.limitElement.clone();
resultExprs = Expr.cloneList(other.resultExprs);
baseTblResultExprs = Expr.cloneList(other.baseTblResultExprs);
aliasSMap = other.aliasSMap.clone();
mvSMap = other.mvSMap.clone();
ambiguousAliasList = Expr.cloneList(other.ambiguousAliasList);
sortInfo = (other.sortInfo != null) ? other.sortInfo.clone() : null;
analyzer = other.analyzer;
evaluateOrderBy = other.evaluateOrderBy;
disableTuplesMVRewriter = other.disableTuplesMVRewriter;
}
@Override
public void reset() {
super.reset();
if (orderByElements != null) {
for (OrderByElement o : orderByElements) {
o.getExpr().reset();
}
}
limitElement.reset();
resultExprs.clear();
baseTblResultExprs.clear();
aliasSMap.clear();
ambiguousAliasList.clear();
orderByElementsAfterAnalyzed = null;
sortInfo = null;
evaluateOrderBy = false;
fromInsert = false;
}
// DORIS-7361, Reset selectList to keep clean
public abstract void resetSelectList();
public void setFromInsert(boolean value) {
this.fromInsert = value;
}
public boolean isFromInsert() {
return fromInsert;
}
@Override
public abstract QueryStmt clone();
public abstract void substituteSelectList(Analyzer analyzer, List<String> newColLabels)
throws AnalysisException, UserException;
public void setOutFileClause(OutFileClause outFileClause) {
this.outFileClause = outFileClause;
}
public OutFileClause getOutFileClause() {
return outFileClause;
}
public boolean hasOutFileClause() {
return outFileClause != null;
}
public String toSqlWithSelectList() {
toSQLWithSelectList = true;
return toSql();
}
public boolean isPointQuery() {
return isPointQuery;
}
public String toSqlWithHint() {
toSQLWithHint = true;
return toSql();
}
public void setToSQLWithHint(boolean enableSqlSqlWithHint) {
this.toSQLWithHint = enableSqlSqlWithHint;
}
}