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
+}


Reply via email to