This is an automated email from the ASF dual-hosted git repository.
joemcdonnell pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/impala.git
The following commit(s) were added to refs/heads/master by this push:
new 92f54d497 IMPALA-13841: Refactor AnalysisResult to make it immutable
and simpler
92f54d497 is described below
commit 92f54d497f876abf097a5c62da3351bcc2c52f53
Author: Steve Carlin <[email protected]>
AuthorDate: Thu Mar 6 10:21:06 2025 -0800
IMPALA-13841: Refactor AnalysisResult to make it immutable and simpler
This refactoring is needed as a pre-step to adding analysis for the
Calcite Planner
The AnalysisResult class should be an class with immutable members with
the results obtained from analyzing the query. The Planner step which
follows should then be able to use the AnalysisResult to obtain the analysis
information. To keep it clean, AnalysisResult should not have any methods
like "createAnalyzer", something that produces a new object.
A new interface (and its implementor), AnalysisDriver has only one method
"analyze" which produces the AnalysisResult. The Calcite planner will
eventually implement this interface to produce its own AnalysisResult
(or a class derived from AnalysisResult) used by the framework.
Jira ticket IMPALA-13840 has been filed to deal with some code that was
duplicated.
The code in many places can be made simpler if there were a StatementType
enum
dealing with the types of StatementBase.
While the goal was to make AnalysisResult immutable, a bit more refactoring
has to be done to achieve this completely. The userHasProfileAccess_ member
is
still mutable because it is changed in the AuthorizationChecker. This would
involve a more extensive change. Jira ticket IMPALA-13848 has been filed.
Change-Id: Idaf8854b1ce18c72a49893fc36e2cea77b7a2485
Reviewed-on: http://gerrit.cloudera.org:8080/22591
Reviewed-by: Michael Smith <[email protected]>
Tested-by: Michael Smith <[email protected]>
Reviewed-by: Joe McDonnell <[email protected]>
---
.../apache/impala/analysis/AnalysisContext.java | 430 ++++++++++++---------
.../org/apache/impala/analysis/AnalysisDriver.java | 39 ++
.../org/apache/impala/analysis/StmtRewriter.java | 25 +-
.../java/org/apache/impala/service/Frontend.java | 1 +
.../impala/analysis/ExprRewriteRulesTest.java | 3 +-
.../org/apache/impala/common/FrontendFixture.java | 4 +-
.../org/apache/impala/common/FrontendTestBase.java | 8 +-
.../org/apache/impala/common/QueryFixture.java | 3 +-
8 files changed, 309 insertions(+), 204 deletions(-)
diff --git a/fe/src/main/java/org/apache/impala/analysis/AnalysisContext.java
b/fe/src/main/java/org/apache/impala/analysis/AnalysisContext.java
index b23dc9a71..6d3629008 100644
--- a/fe/src/main/java/org/apache/impala/analysis/AnalysisContext.java
+++ b/fe/src/main/java/org/apache/impala/analysis/AnalysisContext.java
@@ -74,6 +74,8 @@ public class AnalysisContext {
public FeCatalog getCatalog() { return catalog_; }
public TQueryCtx getQueryCtx() { return queryCtx_; }
+ public AuthorizationFactory getAuthzFactory() { return authzFactory_; }
+ public boolean getUseHiveColLabels() { return useHiveColLabels_; }
public TQueryOptions getQueryOptions() {
return queryCtx_.client_request.query_options;
}
@@ -85,10 +87,21 @@ public class AnalysisContext {
}
static public class AnalysisResult {
- private StatementBase stmt_;
- private Analyzer analyzer_;
+ private final StatementBase stmt_;
+ private final Analyzer analyzer_;
+ private final ImpalaException exception_;
private boolean userHasProfileAccess_ = true;
+ public AnalysisResult(StatementBase stmt, Analyzer analyzer) {
+ this(stmt, analyzer, null);
+ }
+
+ public AnalysisResult(StatementBase stmt, Analyzer analyzer,
ImpalaException e) {
+ stmt_ = stmt;
+ analyzer_ = analyzer;
+ exception_ = e;
+ }
+
public boolean isAlterTableStmt() { return stmt_ instanceof
AlterTableStmt; }
public boolean isAlterViewStmt() { return stmt_ instanceof AlterViewStmt; }
public boolean isComputeStatsStmt() { return stmt_ instanceof
ComputeStatsStmt; }
@@ -429,56 +442,14 @@ public class AnalysisContext {
public StatementBase getStmt() { return stmt_; }
public Analyzer getAnalyzer() { return analyzer_; }
+ public ImpalaException getException() { return exception_; }
public Set<TAccessEvent> getAccessEvents() { return
analyzer_.getAccessEvents(); }
- public boolean canRewriteStatement() {
- return !isCreateViewStmt() && !isAlterViewStmt() &&
!isShowCreateTableStmt();
- }
- public boolean requiresSubqueryRewrite() {
- return canRewriteStatement() && analyzer_.containsSubquery();
- }
- public boolean requiresAcidComplexScanRewrite() {
- return canRewriteStatement() &&
analyzer_.hasTopLevelAcidCollectionTableRef();
- }
- public boolean requiresZippingUnnestRewrite() {
- return canRewriteStatement() && isZippingUnnestInSelectList(stmt_);
- }
- public boolean requiresExprRewrite() {
- return isQueryStmt() || isInsertStmt() || isCreateTableAsSelectStmt()
- || isUpdateStmt() || isDeleteStmt() || isOptimizeStmt() ||
isMergeStmt();
- }
- public boolean requiresSetOperationRewrite() {
- return analyzer_.containsSetOperation() && !isCreateViewStmt() &&
!isAlterViewStmt()
- && !isShowCreateTableStmt();
- }
public TLineageGraph getThriftLineageGraph() {
return analyzer_.getThriftSerializedLineageGraph();
}
public void setUserHasProfileAccess(boolean value) { userHasProfileAccess_
= value; }
public boolean userHasProfileAccess() { return userHasProfileAccess_; }
- private boolean isZippingUnnestInSelectList(StatementBase stmt) {
- if (!(stmt instanceof SelectStmt)) return false;
- if (!stmt.analyzer_.getTableRefsFromUnnestExpr().isEmpty()) return true;
- SelectStmt selectStmt = (SelectStmt)stmt;
- for (TableRef tblRef : selectStmt.fromClause_.getTableRefs()) {
- if (tblRef instanceof InlineViewRef &&
-
isZippingUnnestInSelectList(((InlineViewRef)tblRef).getViewStmt())) {
- return true;
- }
- }
- return false;
- }
- }
-
- public Analyzer createAnalyzer(StmtTableCache stmtTableCache) {
- return createAnalyzer(stmtTableCache, null);
- }
-
- public Analyzer createAnalyzer(StmtTableCache stmtTableCache,
- AuthorizationContext authzCtx) {
- Analyzer result = new Analyzer(stmtTableCache, queryCtx_, authzFactory_,
authzCtx);
- result.setUseHiveColLabels(useHiveColLabels_);
- return result;
}
public AnalysisResult analyzeAndAuthorize(StatementBase stmt,
@@ -498,28 +469,25 @@ public class AnalysisContext {
StmtTableCache stmtTableCache, AuthorizationChecker authzChecker,
boolean disableAuthorization) throws ImpalaException {
// TODO: Clean up the creation/setting of the analysis result.
- analysisResult_ = new AnalysisResult();
- analysisResult_.stmt_ = stmt;
catalog_ = stmtTableCache.catalog;
// Analyze statement and record exception.
- AnalysisException analysisException = null;
TClientRequest clientRequest = queryCtx_.getClient_request();
AuthorizationContext authzCtx =
authzChecker.createAuthorizationContext(true,
clientRequest.isSetRedacted_stmt() ?
clientRequest.getRedacted_stmt() : clientRequest.getStmt(),
queryCtx_.getSession(), Optional.of(timeline_));
Preconditions.checkState(authzCtx != null);
- try {
- analyze(stmtTableCache, authzCtx);
- } catch (AnalysisException e) {
- analysisException = e;
- } finally {
- authzChecker.postAnalyze(authzCtx);
- }
+ AnalysisDriverImpl analysisDriver =
+ new AnalysisDriverImpl(this, stmt, stmtTableCache, authzCtx);
+
+ analysisResult_ = analysisDriver.analyze();
+ authzChecker.postAnalyze(authzCtx);
+ ImpalaException analysisException = analysisResult_.getException();
+
// A statement that returns at most one row does not need to spool query
results.
- if (analysisException == null && analysisResult_.stmt_ instanceof
SelectStmt &&
- ((SelectStmt)analysisResult_.stmt_).returnsAtMostOneRow()) {
+ if (analysisException == null && analysisResult_.getStmt() instanceof
SelectStmt &&
+ ((SelectStmt)analysisResult_.getStmt()).returnsAtMostOneRow()) {
clientRequest.query_options.setSpool_query_results(false);
if (LOG.isTraceEnabled()) {
LOG.trace("Result spooling is disabled due to the statement returning
at most "
@@ -555,144 +523,234 @@ public class AnalysisContext {
}
/**
- * Analyzes the statement set in 'analysisResult_' with a new Analyzer based
on the
- * given loaded tables. Performs expr and subquery rewrites which require
re-analyzing
- * the transformed statement.
+ * AnalysisDriverImpl has one main method "analyze" which drives the analysis
+ * of the query. The analyze method returns an AnalysisResult which is a
simple
+ * class containing results from the analysis which are needed for the
planning
+ * stage.
*/
- private void analyze(StmtTableCache stmtTableCache, AuthorizationContext
authzCtx)
- throws AnalysisException {
- Preconditions.checkNotNull(analysisResult_);
- Preconditions.checkNotNull(analysisResult_.stmt_);
- analysisResult_.analyzer_ = createAnalyzer(stmtTableCache, authzCtx);
- analysisResult_.stmt_.analyze(analysisResult_.analyzer_);
- // Enforce the statement expression limit at the end of analysis so that
there is an
- // accurate count of the total number of expressions. The first analyze()
call is not
- // very expensive (~seconds) even for large statements. The limit on the
total length
- // of the SQL statement (max_statement_length_bytes) provides an upper
bound.
- // It is important to enforce this before expression rewrites, because
rewrites are
- // expensive with large expression trees. For example, a SQL that takes a
few seconds
- // to analyze the first time may take 10 minutes for rewrites.
- analysisResult_.analyzer_.checkStmtExprLimit();
-
- // The rewrites should have no user-visible effect on query results,
including types
- // and labels. Remember the original result types and column labels to
restore them
- // after the rewritten stmt has been reset() and re-analyzed. For a CTAS
statement,
- // the types represent column types of the table that will be created,
including the
- // partition columns, if any.
- List<Type> origResultTypes = new ArrayList<>();
- for (Expr e : analysisResult_.stmt_.getResultExprs()) {
- origResultTypes.add(e.getType());
- }
- List<String> origColLabels =
- Lists.newArrayList(analysisResult_.stmt_.getColLabels());
-
- // Apply column/row masking, expr, setop, and subquery rewrites.
- boolean shouldReAnalyze = false;
- if (authzFactory_.getAuthorizationConfig().isEnabled()) {
- shouldReAnalyze =
analysisResult_.stmt_.resolveTableMask(analysisResult_.analyzer_);
- // If any catalog table/view is replaced by table masking views, we need
to
- // resolve them. Also re-analyze the SlotRefs to reference the output
exprs of
- // the table masking views.
- if (shouldReAnalyze) {
- // To be consistent with Hive, privilege requests introduced by the
masking views
- // should also be collected (IMPALA-10728).
- reAnalyze(stmtTableCache, authzCtx, origResultTypes, origColLabels,
- /*collectPrivileges*/ true);
- }
- shouldReAnalyze = false;
- }
- ExprRewriter rewriter = analysisResult_.analyzer_.getExprRewriter();
- if (analysisResult_.requiresExprRewrite()) {
- rewriter.reset();
- analysisResult_.stmt_.rewriteExprs(rewriter);
- shouldReAnalyze = rewriter.changed();
- }
- if (analysisResult_.requiresSubqueryRewrite()) {
- new StmtRewriter.SubqueryRewriter().rewrite(analysisResult_);
- shouldReAnalyze = true;
- }
- if (analysisResult_.requiresSetOperationRewrite()) {
- new StmtRewriter().rewrite(analysisResult_);
- shouldReAnalyze = true;
- }
- if (analysisResult_.requiresAcidComplexScanRewrite()) {
- new StmtRewriter.AcidRewriter().rewrite(analysisResult_);
- shouldReAnalyze = true;
- }
- if (analysisResult_.requiresZippingUnnestRewrite()) {
- new StmtRewriter.ZippingUnnestRewriter().rewrite(analysisResult_);
- shouldReAnalyze = true;
- }
- if (!shouldReAnalyze) return;
-
- // For SetOperationStmt we must replace the query statement with the
rewritten version
- // before re-analysis and set the explain flag of the rewritten version if
the
- // original is explain statement.
- if (analysisResult_.requiresSetOperationRewrite()) {
- if (analysisResult_.isSetOperationStmt()) {
- if (((SetOperationStmt) analysisResult_.getStmt()).hasRewrittenStmt())
{
- boolean isExplain = analysisResult_.isExplainStmt();
- analysisResult_.stmt_ =
- ((SetOperationStmt) analysisResult_.getStmt()).getRewrittenStmt();
- if (isExplain) analysisResult_.stmt_.setIsExplain();
+ public static class AnalysisDriverImpl implements AnalysisDriver {
+ private StatementBase stmt_;
+ private Analyzer analyzer_;
+ private final AnalysisContext ctx_;
+ private final StmtTableCache stmtTableCache_;
+ private final AuthorizationContext authzCtx_;
+
+ public AnalysisDriverImpl(AnalysisContext ctx, StatementBase stmt,
+ StmtTableCache stmtTableCache,
+ AuthorizationContext authzCtx) {
+ Preconditions.checkNotNull(stmt);
+ ctx_ = ctx;
+ stmt_ = stmt;
+ stmtTableCache_ = stmtTableCache;
+ authzCtx_ = authzCtx;
+ analyzer_ = createAnalyzer(ctx_, stmtTableCache, authzCtx);
+ }
+
+ /**
+ * Analyzes the statement set in 'analysisResult_' with a new Analyzer
based on the
+ * given loaded tables. Performs expr and subquery rewrites which require
re-analyzing
+ * the transformed statement.
+ */
+ @Override
+ public AnalysisResult analyze() {
+ try {
+ stmt_.analyze(analyzer_);
+ // Enforce the statement expression limit at the end of analysis so
that there is
+ // an accurate count of the total number of expressions. The first
analyze() call
+ // is not very expensive (~seconds) even for large statements. The
limit on the
+ // total length of the SQL statement (max_statement_length_bytes)
provides an
+ // upper bound. It is important to enforce this before expression
rewrites,
+ // because rewrites are expensive with large expression trees. For
example, a SQL
+ // that takes a few seconds to analyze the first time may take 10
minutes for
+ // rewrites.
+ analyzer_.checkStmtExprLimit();
+
+ // The rewrites should have no user-visible effect on query results,
including
+ // types and labels. Remember the original result types and column
labels to
+ // restore them after the rewritten stmt has been reset() and
re-analyzed. For a
+ // CTAS statement, the types represent column types of the table that
will be
+ // created, including the partition columns, if any.
+ List<Type> origResultTypes = new ArrayList<>();
+ for (Expr e : stmt_.getResultExprs()) {
+ origResultTypes.add(e.getType());
+ }
+ List<String> origColLabels =
+ Lists.newArrayList(stmt_.getColLabels());
+
+ // Apply column/row masking, expr, setop, and subquery rewrites.
+ boolean shouldReAnalyze = false;
+ if (ctx_.getAuthzFactory().getAuthorizationConfig().isEnabled()) {
+ shouldReAnalyze = stmt_.resolveTableMask(analyzer_);
+ // If any catalog table/view is replaced by table masking views, we
need to
+ // resolve them. Also re-analyze the SlotRefs to reference the
output exprs of
+ // the table masking views.
+ if (shouldReAnalyze) {
+ // To be consistent with Hive, privilege requests introduced by
the masking
+ // views should also be collected (IMPALA-10728).
+ reAnalyze(stmtTableCache_, authzCtx_, origResultTypes,
origColLabels,
+ /*collectPrivileges*/ true);
+ }
+ shouldReAnalyze = false;
+ }
+ ExprRewriter rewriter = analyzer_.getExprRewriter();
+ if (requiresExprRewrite()) {
+ rewriter.reset();
+ stmt_.rewriteExprs(rewriter);
+ shouldReAnalyze = rewriter.changed();
+ }
+ if (requiresSubqueryRewrite()) {
+ new StmtRewriter.SubqueryRewriter().rewrite(stmt_);
+ shouldReAnalyze = true;
+ }
+ if (requiresSetOperationRewrite()) {
+ new StmtRewriter().rewrite(stmt_);
+ shouldReAnalyze = true;
+ }
+ if (requiresAcidComplexScanRewrite()) {
+ new StmtRewriter.AcidRewriter().rewrite(stmt_);
+ shouldReAnalyze = true;
+ }
+ if (requiresZippingUnnestRewrite()) {
+ new StmtRewriter.ZippingUnnestRewriter().rewrite(stmt_);
+ shouldReAnalyze = true;
+ }
+ if (!shouldReAnalyze) {
+ return new AnalysisResult(stmt_, analyzer_);
+ }
+
+ // For SetOperationStmt we must replace the query statement with the
rewritten
+ // version before re-analysis and set the explain flag of the
rewritten version
+ // if the original is explain statement.
+ if (requiresSetOperationRewrite()) {
+ if (stmt_ instanceof SetOperationStmt) {
+ if (((SetOperationStmt) stmt_).hasRewrittenStmt()) {
+ boolean isExplain = stmt_.isExplain();
+ stmt_ = ((SetOperationStmt) stmt_).getRewrittenStmt();
+ if (isExplain) stmt_.setIsExplain();
+ }
+ }
}
+
+ reAnalyze(stmtTableCache_, authzCtx_, origResultTypes, origColLabels,
+ /*collectPrivileges*/ false);
+ Preconditions.checkState(!requiresSubqueryRewrite());
+ return new AnalysisResult(stmt_, analyzer_);
+ } catch (ImpalaException e) {
+ return new AnalysisResult(stmt_, analyzer_, e);
}
}
- reAnalyze(stmtTableCache, authzCtx, origResultTypes, origColLabels,
- /*collectPrivileges*/ false);
- Preconditions.checkState(!analysisResult_.requiresSubqueryRewrite());
- }
+ private void reAnalyze(
+ StmtTableCache stmtTableCache, AuthorizationContext authzCtx,
+ List<Type> origResultTypes, List<String> origColLabels, boolean
collectPrivileges)
+ throws AnalysisException {
+ boolean isExplain = stmt_.isExplain();
+ // Some expressions, such as function calls with constant arguments, can
get
+ // folded into literals. Since literals do not require privilege
requests, we
+ // must save the original privileges in order to not lose them during
+ // re-analysis.
+ ImmutableList<PrivilegeRequest> origPrivReqs =
analyzer_.getPrivilegeReqs();
+
+ // Re-analyze the stmt with a new analyzer.
+ analyzer_ = createAnalyzer(ctx_, stmtTableCache, authzCtx);
+ // Restore privilege requests found during the previous pass
+ for (PrivilegeRequest req : origPrivReqs) {
+ analyzer_.registerPrivReq(req);
+ }
+ // Only collect privilege requests in need.
+ analyzer_.setEnablePrivChecks(collectPrivileges);
+ stmt_.reset();
+ try {
+ stmt_.analyze(analyzer_);
+ analyzer_.setEnablePrivChecks(true); // Always restore
+ } catch (AnalysisException e) {
+ logRewriteErrorNoThrow(stmt_, e);
+ throw new AnalysisException("An error occurred after query rewrite: " +
+ e.getMessage(), e);
+ }
+ // Restore the original result types and column labels.
+ stmt_.castResultExprs(origResultTypes);
+ stmt_.setColLabels(origColLabels);
+ if (LOG.isTraceEnabled()) {
+ LOG.trace("Rewritten SQL: " + stmt_.toSql(REWRITTEN));
+ }
+ if (isExplain) stmt_.setIsExplain();
+ }
- private void reAnalyze(StmtTableCache stmtTableCache, AuthorizationContext
authzCtx,
- List<Type> origResultTypes, List<String> origColLabels, boolean
collectPrivileges)
- throws AnalysisException {
- boolean isExplain = analysisResult_.isExplainStmt();
- // Some expressions, such as function calls with constant arguments, can
get
- // folded into literals. Since literals do not require privilege requests,
we
- // must save the original privileges in order to not lose them during
- // re-analysis.
- ImmutableList<PrivilegeRequest> origPrivReqs =
- analysisResult_.analyzer_.getPrivilegeReqs();
-
- // Re-analyze the stmt with a new analyzer.
- analysisResult_.analyzer_ = createAnalyzer(stmtTableCache, authzCtx);
- // Restore privilege requests found during the previous pass
- for (PrivilegeRequest req : origPrivReqs) {
- analysisResult_.analyzer_.registerPrivReq(req);
- }
- // Only collect privilege requests in need.
- analysisResult_.analyzer_.setEnablePrivChecks(collectPrivileges);
- analysisResult_.stmt_.reset();
- try {
- analysisResult_.stmt_.analyze(analysisResult_.analyzer_);
- analysisResult_.analyzer_.setEnablePrivChecks(true); // Always restore
- } catch (AnalysisException e) {
- logRewriteErrorNoThrow(analysisResult_.stmt_, e);
- throw new AnalysisException("An error occurred after query rewrite: " +
- e.getMessage(), e);
- }
- // Restore the original result types and column labels.
- analysisResult_.stmt_.castResultExprs(origResultTypes);
- analysisResult_.stmt_.setColLabels(origColLabels);
- if (LOG.isTraceEnabled()) {
- LOG.trace("Rewritten SQL: " + analysisResult_.stmt_.toSql(REWRITTEN));
- }
- if (isExplain) analysisResult_.stmt_.setIsExplain();
- }
+ private void logRewriteErrorNoThrow(StatementBase stmt,
+ AnalysisException analysisException) {
+ try {
+ LOG.error(String.format("Error analyzing the rewritten query.\n" +
+ "Original SQL: %s\nRewritten SQL: %s", stmt.toSql(),
+ stmt.toSql(REWRITTEN)), analysisException);
+ } catch (Exception e) {
+ LOG.error("An exception occurred during printing out " +
+ "the rewritten SQL statement.", e);
+ }
+ }
- private void logRewriteErrorNoThrow(StatementBase stmt,
- AnalysisException analysisException) {
- try {
- LOG.error(String.format("Error analyzing the rewritten query.\n" +
- "Original SQL: %s\nRewritten SQL: %s", stmt.toSql(),
- stmt.toSql(REWRITTEN)), analysisException);
- } catch (Exception e) {
- LOG.error("An exception occurred during printing out " +
- "the rewritten SQL statement.", e);
+ public boolean canRewriteStatement() {
+ return !isCreateViewStmt() && !isAlterViewStmt() &&
!isShowCreateTableStmt();
+ }
+ public boolean requiresSubqueryRewrite() {
+ return canRewriteStatement() && analyzer_.containsSubquery();
+ }
+ public boolean requiresAcidComplexScanRewrite() {
+ return canRewriteStatement() &&
analyzer_.hasTopLevelAcidCollectionTableRef();
+ }
+ public boolean requiresZippingUnnestRewrite() {
+ return canRewriteStatement() && isZippingUnnestInSelectList(stmt_);
+ }
+ public boolean requiresExprRewrite() {
+ return isQueryStmt() || isInsertStmt() || isCreateTableAsSelectStmt()
+ || isUpdateStmt() || isDeleteStmt() || isOptimizeStmt() ||
isMergeStmt();
+ }
+ public boolean requiresSetOperationRewrite() {
+ return analyzer_.containsSetOperation() && canRewriteStatement();
}
- }
+ // TODO: IMPALA-13840: Code would be cleaner if we had an enum for
StatementType
+ // rather than checking "instanceof".
+ public boolean isCreateViewStmt() { return stmt_ instanceof
CreateViewStmt; }
+ public boolean isAlterViewStmt() { return stmt_ instanceof AlterViewStmt; }
+ public boolean isShowCreateTableStmt() {
+ return stmt_ instanceof ShowCreateTableStmt;
+ }
+ public boolean isQueryStmt() { return stmt_ instanceof QueryStmt; }
+ public boolean isInsertStmt() { return stmt_ instanceof InsertStmt; }
+ public boolean isMergeStmt() { return stmt_ instanceof MergeStmt; }
+ public boolean isDeleteStmt() { return stmt_ instanceof DeleteStmt; }
+ public boolean isOptimizeStmt() { return stmt_ instanceof OptimizeStmt; }
+ public boolean isUpdateStmt() { return stmt_ instanceof UpdateStmt; }
+ public boolean isCreateTableAsSelectStmt() {
+ return stmt_ instanceof CreateTableAsSelectStmt;
+ }
+ private boolean isZippingUnnestInSelectList(StatementBase stmt) {
+ if (!(stmt instanceof SelectStmt)) return false;
+ if (!stmt.analyzer_.getTableRefsFromUnnestExpr().isEmpty()) return true;
+ SelectStmt selectStmt = (SelectStmt)stmt;
+ for (TableRef tblRef : selectStmt.fromClause_.getTableRefs()) {
+ if (tblRef instanceof InlineViewRef &&
+
isZippingUnnestInSelectList(((InlineViewRef)tblRef).getViewStmt())) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public static Analyzer createAnalyzer(AnalysisContext ctx,
+ StmtTableCache stmtTableCache) {
+ return createAnalyzer(ctx, stmtTableCache, null);
+ }
+
+ private static Analyzer createAnalyzer(AnalysisContext ctx,
+ StmtTableCache stmtTableCache, AuthorizationContext authzCtx) {
+ Analyzer result = new Analyzer(stmtTableCache, ctx.getQueryCtx(),
+ ctx.getAuthzFactory(), authzCtx);
+ result.setUseHiveColLabels(ctx.getUseHiveColLabels());
+ return result;
+ }
+ }
public Analyzer getAnalyzer() { return analysisResult_.getAnalyzer(); }
public EventSequence getTimeline() { return timeline_; }
// This should only be called after analyzeAndAuthorize().
diff --git a/fe/src/main/java/org/apache/impala/analysis/AnalysisDriver.java
b/fe/src/main/java/org/apache/impala/analysis/AnalysisDriver.java
new file mode 100644
index 000000000..cab02a357
--- /dev/null
+++ b/fe/src/main/java/org/apache/impala/analysis/AnalysisDriver.java
@@ -0,0 +1,39 @@
+// 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.impala.analysis;
+
+import org.apache.impala.analysis.AnalysisContext.AnalysisResult;
+
+/**
+ * Interface for the analyze method which returns an AnalysisResult.
+ *
+ * The AnalysisDriver interface allows the existence of multiple planners to
+ * implement how each one does analysis. Namely, the Calcite Planner analyzes
+ * the statement differently from the way the original Impala planner does.
+ *
+ * The "analyze" method here does not throw an exception. The exception
handling
+ * is handled within the analyze method and the exception should be placed
within the
+ * AnalysisResult. The authorization checker needs the analysis information
whether
+ * it succeeds or fails. This is because an authorization exception would
supercede
+ * an analysis exception, as the end user should not be able to see messages
+ * like 'column <x> not found' if they do not have authorization rights to view
+ * the table.
+ */
+public interface AnalysisDriver {
+ public AnalysisResult analyze();
+}
diff --git a/fe/src/main/java/org/apache/impala/analysis/StmtRewriter.java
b/fe/src/main/java/org/apache/impala/analysis/StmtRewriter.java
index 0a2185f40..5b0868d71 100644
--- a/fe/src/main/java/org/apache/impala/analysis/StmtRewriter.java
+++ b/fe/src/main/java/org/apache/impala/analysis/StmtRewriter.java
@@ -52,26 +52,25 @@ public class StmtRewriter {
* Rewrite the statement of an analysis result in-place. Assumes that
BetweenPredicates
* have already been rewritten.
*/
- public void rewrite(AnalysisResult analysisResult) throws AnalysisException {
+ public void rewrite(StatementBase stmt) throws AnalysisException {
// Analyzed stmt that contains a query statement with subqueries to be
rewritten.
- StatementBase stmt = analysisResult.getStmt();
Preconditions.checkState(stmt.isAnalyzed());
// Analyzed query statement to be rewritten.
QueryStmt queryStmt;
if (stmt instanceof QueryStmt) {
- queryStmt = (QueryStmt) analysisResult.getStmt();
+ queryStmt = (QueryStmt) stmt;
} else if (stmt instanceof InsertStmt) {
- queryStmt = ((InsertStmt) analysisResult.getStmt()).getQueryStmt();
+ queryStmt = ((InsertStmt) stmt).getQueryStmt();
} else if (stmt instanceof CreateTableAsSelectStmt) {
- queryStmt = ((CreateTableAsSelectStmt)
analysisResult.getStmt()).getQueryStmt();
- } else if (analysisResult.isUpdateStmt()) {
- queryStmt = ((UpdateStmt) analysisResult.getStmt()).getQueryStmt();
- } else if (analysisResult.isDeleteStmt()) {
- queryStmt = ((DeleteStmt) analysisResult.getStmt()).getQueryStmt();
- } else if (analysisResult.isMergeStmt()) {
- queryStmt = ((MergeStmt) analysisResult.getStmt()).getQueryStmt();
- } else if (analysisResult.isTestCaseStmt()) {
- queryStmt = ((CopyTestCaseStmt) analysisResult.getStmt()).getQueryStmt();
+ queryStmt = ((CreateTableAsSelectStmt) stmt).getQueryStmt();
+ } else if (stmt instanceof UpdateStmt) {
+ queryStmt = ((UpdateStmt) stmt).getQueryStmt();
+ } else if (stmt instanceof DeleteStmt) {
+ queryStmt = ((DeleteStmt) stmt).getQueryStmt();
+ } else if (stmt instanceof MergeStmt) {
+ queryStmt = ((MergeStmt) stmt).getQueryStmt();
+ } else if (stmt instanceof CopyTestCaseStmt) {
+ queryStmt = ((CopyTestCaseStmt) stmt).getQueryStmt();
} else {
throw new AnalysisException("Unsupported statement: " + stmt.toSql());
}
diff --git a/fe/src/main/java/org/apache/impala/service/Frontend.java
b/fe/src/main/java/org/apache/impala/service/Frontend.java
index 0a2710f86..f1f1cfdab 100644
--- a/fe/src/main/java/org/apache/impala/service/Frontend.java
+++ b/fe/src/main/java/org/apache/impala/service/Frontend.java
@@ -2739,6 +2739,7 @@ public class Frontend {
AnalysisContext analysisCtx = new AnalysisContext(queryCtx, authzFactory_,
timeline);
AnalysisResult analysisResult = analysisCtx.analyzeAndAuthorize(stmt,
stmtTableCache,
authzChecker_.get(), planCtx.compilationState_.disableAuthorization());
+ Preconditions.checkState(analysisResult.getException() == null);
if (!planCtx.compilationState_.disableAuthorization()) {
LOG.info("Analysis and authorization finished.");
planCtx.compilationState_.setUserHasProfileAccess(
diff --git
a/fe/src/test/java/org/apache/impala/analysis/ExprRewriteRulesTest.java
b/fe/src/test/java/org/apache/impala/analysis/ExprRewriteRulesTest.java
index 4472cc61b..c8571c0b1 100644
--- a/fe/src/test/java/org/apache/impala/analysis/ExprRewriteRulesTest.java
+++ b/fe/src/test/java/org/apache/impala/analysis/ExprRewriteRulesTest.java
@@ -24,6 +24,7 @@ import static org.junit.Assert.fail;
import java.util.ArrayList;
import java.util.List;
+import org.apache.impala.analysis.AnalysisContext.AnalysisDriverImpl;
import org.apache.impala.catalog.ScalarType;
import org.apache.impala.common.AnalysisException;
import org.apache.impala.common.AnalysisSessionFixture;
@@ -93,7 +94,7 @@ public class ExprRewriteRulesTest extends FrontendTestBase {
Preconditions.checkState(analyzer_ == null, "Already analyzed");
stmt_ = parse();
analysisCtx_ = makeAnalysisContext();
- analyzer_ = analysisCtx_.createAnalyzer(makeTableCache(stmt_));
+ analyzer_ = AnalysisDriverImpl.createAnalyzer(analysisCtx_,
makeTableCache(stmt_));
stmt_.analyze(analyzer_);
return stmt_;
}
diff --git a/fe/src/test/java/org/apache/impala/common/FrontendFixture.java
b/fe/src/test/java/org/apache/impala/common/FrontendFixture.java
index 56a9ac91b..94f241209 100644
--- a/fe/src/test/java/org/apache/impala/common/FrontendFixture.java
+++ b/fe/src/test/java/org/apache/impala/common/FrontendFixture.java
@@ -367,8 +367,10 @@ public class FrontendFixture {
StmtMetadataLoader mdLoader = new StmtMetadataLoader(
frontend_, ctx.getQueryCtx().session.database, null, user, null);
StmtTableCache stmtTableCache = mdLoader.loadTables(parsedStmt);
- return ctx.analyzeAndAuthorize(parsedStmt, stmtTableCache,
+ AnalysisResult analysisResult = ctx.analyzeAndAuthorize(parsedStmt,
stmtTableCache,
frontend_.getAuthzChecker());
+ Preconditions.checkState(analysisResult.getException() == null);
+ return analysisResult;
}
/**
diff --git a/fe/src/test/java/org/apache/impala/common/FrontendTestBase.java
b/fe/src/test/java/org/apache/impala/common/FrontendTestBase.java
index 14e7371fb..5e7611025 100644
--- a/fe/src/test/java/org/apache/impala/common/FrontendTestBase.java
+++ b/fe/src/test/java/org/apache/impala/common/FrontendTestBase.java
@@ -27,6 +27,7 @@ import java.util.Set;
import java.util.function.Supplier;
import org.apache.impala.analysis.AnalysisContext;
+import org.apache.impala.analysis.AnalysisContext.AnalysisDriverImpl;
import org.apache.impala.analysis.AnalysisContext.AnalysisResult;
import org.apache.impala.analysis.Analyzer;
import org.apache.impala.analysis.InsertStmt;
@@ -277,7 +278,7 @@ public class FrontendTestBase extends AbstractFrontendTest {
StmtMetadataLoader mdLoader =
new StmtMetadataLoader(frontend_,
ctx.getQueryCtx().session.database, null);
StmtTableCache loadedTables = mdLoader.loadTables(stmt);
- Analyzer analyzer = ctx.createAnalyzer(loadedTables);
+ Analyzer analyzer = AnalysisDriverImpl.createAnalyzer(ctx, loadedTables);
stmt.analyze(analyzer);
return stmt;
}
@@ -347,7 +348,10 @@ public class FrontendTestBase extends AbstractFrontendTest
{
StmtMetadataLoader mdLoader = new StmtMetadataLoader(
fe, ctx.getQueryCtx().session.database, null, user, null);
StmtTableCache stmtTableCache = mdLoader.loadTables(parsedStmt);
- return ctx.analyzeAndAuthorize(parsedStmt, stmtTableCache,
fe.getAuthzChecker());
+ AnalysisResult analysisResult =
+ ctx.analyzeAndAuthorize(parsedStmt, stmtTableCache,
fe.getAuthzChecker());
+ Preconditions.checkState(analysisResult.getException() == null);
+ return analysisResult;
}
}
diff --git a/fe/src/test/java/org/apache/impala/common/QueryFixture.java
b/fe/src/test/java/org/apache/impala/common/QueryFixture.java
index cc550d375..7d17931e1 100644
--- a/fe/src/test/java/org/apache/impala/common/QueryFixture.java
+++ b/fe/src/test/java/org/apache/impala/common/QueryFixture.java
@@ -76,6 +76,7 @@ public class QueryFixture {
analysisCtx_ = makeAnalysisContext();
analysisResult_ = analysisCtx_.analyzeAndAuthorize(stmt_,
makeTableCache(stmt_), session_.frontend().getAuthzChecker());
+ Preconditions.checkState(analysisResult_.getException() == null);
Preconditions.checkNotNull(analysisResult_.getStmt());
return stmt_;
} catch (AnalysisException e) {
@@ -258,4 +259,4 @@ public class QueryFixture {
throw new IllegalStateException(e);
}
}
-}
\ No newline at end of file
+}