@SuppressWarnings("checkstyle:methodlength")
  void analyzeInternal(ASTNode ast, Supplier<PlannerContext> pcf) throws SemanticException {
    LOG.info("Starting Semantic Analysis");
    PerfLogger perfLogger = SessionState.getPerfLogger();
    perfLogger.perfLogBegin(this.getClass().getName(), PerfLogger.GENERATE_RESOLVED_PARSETREE);
    // 1. Generate Resolved Parse tree from syntax tree
    boolean needsTransform = needsTransform();
    //change the location of position alias process here
    processPositionAlias(ast);
    cacheTableHelper.populateCache(ctx.getParsedTables(), conf, getTxnMgr());
    PlannerContext plannerCtx = pcf.get();
    if (!genResolvedParseTree(ast, plannerCtx)) {
      return;
    }
    if (tablesFromReadEntities(inputs).stream().anyMatch(AcidUtils::isTransactionalTable)) {
      queryState.getValidTxnList();
    }

    if (HiveConf.getBoolVar(conf, ConfVars.HIVE_REMOVE_ORDERBY_IN_SUBQUERY)) {
      for (String alias : qb.getSubqAliases()) {
        removeOBInSubQuery(qb.getSubqForAlias(alias));
      }
    }

    final String llapIOETLSkipFormat = HiveConf.getVar(conf, ConfVars.LLAP_IO_ETL_SKIP_FORMAT);
    if (qb.getParseInfo().hasInsertTables() || qb.isCTAS()) {
      if (llapIOETLSkipFormat.equalsIgnoreCase("encode")) {
        conf.setBoolean(ConfVars.LLAP_IO_ENCODE_ENABLED.varname, false);
        LOG.info("Disabling LLAP IO encode as ETL query is detected");
      } else if (llapIOETLSkipFormat.equalsIgnoreCase("all")) {
        conf.setBoolean(ConfVars.LLAP_IO_ENABLED.varname, false);
        LOG.info("Disabling LLAP IO as ETL query is detected");
      }
    }

    // Check query results cache.
    // If no masking/filtering required, then we can check the cache now, before
    // generating the operator tree and going through CBO.
    // Otherwise we have to wait until after the masking/filtering step.
    boolean isCacheEnabled = isResultsCacheEnabled();
    QueryResultsCache.LookupInfo lookupInfo = null;
    if (isCacheEnabled && !needsTransform && queryTypeCanUseCache(qb)) {
      lookupInfo = createLookupInfoForQuery(ast);
      if (checkResultsCache(lookupInfo, false)) {
        return;
      }
    }

    ASTNode astForMasking;
    if (isCBOExecuted() && needsTransform &&
        (qb.isCTAS() || forViewCreation || qb.isMaterializedView() || qb.isMultiDestQuery())) {
      // If we use CBO and we may apply masking/filtering policies, we create a copy of the ast.
      // The reason is that the generation of the operator tree may modify the initial ast,
      // but if we need to parse for a second time, we would like to parse the unmodified ast.
      astForMasking = (ASTNode) ParseDriver.adaptor.dupTree(ast);
    } else {
      astForMasking = ast;
    }
    perfLogger.perfLogEnd(this.getClass().getName(), PerfLogger.GENERATE_RESOLVED_PARSETREE);

    // 2. Gen OP Tree from resolved Parse Tree
    perfLogger.perfLogBegin(this.getClass().getName(), PerfLogger.LOGICALPLAN_AND_HIVE_OPERATOR_TREE);
    sinkOp = genOPTree(ast, plannerCtx);

    boolean usesMasking = false;
    if (!forViewCreation && ast.getToken().getType() != HiveParser.TOK_CREATE_MATERIALIZED_VIEW &&
        (tableMask.isEnabled() && analyzeRewrite == null)) {
      // Here we rewrite the * and also the masking table
      ParseResult rewrittenResult = rewriteASTWithMaskAndFilter(tableMask, astForMasking, ctx.getTokenRewriteStream(),
          ctx, db);
      ASTNode rewrittenAST = rewrittenResult.getTree();
      if (astForMasking != rewrittenAST) {
        usesMasking = true;
        plannerCtx = pcf.get();
        ctx.setSkipTableMasking(true);
        ctx.setTokenRewriteStream(rewrittenResult.getTokenRewriteStream());
        init(true);
        //change the location of position alias process here
        processPositionAlias(rewrittenAST);
        genResolvedParseTree(rewrittenAST, plannerCtx);
        if (this instanceof CalcitePlanner) {
          ((CalcitePlanner) this).resetCalciteConfiguration();
        }
        sinkOp = genOPTree(rewrittenAST, plannerCtx);
      }
    }

    // validate if this sink operation is allowed for non-native tables
    if (sinkOp instanceof FileSinkOperator) {
      FileSinkOperator fileSinkOperator = (FileSinkOperator) sinkOp;
      Optional<HiveStorageHandler> handler = Optional.ofNullable(fileSinkOperator)
          .map(FileSinkOperator::getConf)
          .map(FileSinkDesc::getTable)
          .map(Table::getStorageHandler);
      if (handler.isPresent()) {
         handler.get().validateSinkDesc(fileSinkOperator.getConf());
      }
    }

    // Check query results cache
    // In the case that row or column masking/filtering was required, we do not support caching.
    // TODO: Enable caching for queries with masking/filtering
    if (isCacheEnabled && needsTransform && !usesMasking && queryTypeCanUseCache(qb)) {
      lookupInfo = createLookupInfoForQuery(ast);
      if (checkResultsCache(lookupInfo, false)) {
        return;
      }
    }
    perfLogger.perfLogEnd(this.getClass().getName(), PerfLogger.LOGICALPLAN_AND_HIVE_OPERATOR_TREE);

    // 3. Deduce Resultset Schema
    perfLogger.perfLogBegin(this.getClass().getName(), PerfLogger.DEDUCE_RESULTSET_SCHEMA);
    if ((forViewCreation || createVwDesc != null) && !this.ctx.isCboSucceeded()) {
      resultSchema = convertRowSchemaToViewSchema(opParseCtx.get(sinkOp).getRowResolver());
    } else {
      // resultSchema will be null if
      // (1) cbo is disabled;
      // (2) or cbo is enabled with AST return path (whether succeeded or not,
      // resultSchema will be re-initialized)
      // It will only be not null if cbo is enabled with new return path and it
      // succeeds.
      if (resultSchema == null) {
        resultSchema = convertRowSchemaToResultSetSchema(opParseCtx.get(sinkOp).getRowResolver(),
            HiveConf.getBoolVar(conf, HiveConf.ConfVars.HIVE_RESULTSET_USE_UNIQUE_COLUMN_NAMES));
      }
    }
    perfLogger.perfLogEnd(this.getClass().getName(), PerfLogger.DEDUCE_RESULTSET_SCHEMA);

    // 4. Generate Parse Context for Optimizer & Physical compiler
    perfLogger.perfLogBegin(this.getClass().getName(), PerfLogger.PARSE_CONTEXT_GENERATION);
    copyInfoToQueryProperties(queryProperties);
    ParseContext pCtx = new ParseContext(queryState, opToPartPruner, opToPartList, topOps,
        new HashSet<JoinOperator>(joinContext.keySet()),
        new HashSet<SMBMapJoinOperator>(smbMapJoinContext.keySet()),
        loadTableWork, loadFileWork, columnStatsAutoGatherContexts, ctx, idToTableNameMap, destTableId, uCtx,
        listMapJoinOpsNoReducer, prunedPartitions, tabNameToTabObject, opToSamplePruner,
        globalLimitCtx, nameToSplitSample, inputs, rootTasks, opToPartToSkewedPruner,
        viewAliasToInput, reduceSinkOperatorsAddedByEnforceBucketingSorting,
        analyzeRewrite, tableDesc, createVwDesc, materializedViewUpdateDesc,
        queryProperties, viewProjectToTableSchema);

    // Set the semijoin hints in parse context
    pCtx.setSemiJoinHints(parseSemiJoinHint(getQB().getParseInfo().getHintList()));
    // Set the mapjoin hint if it needs to be disabled.
    pCtx.setDisableMapJoin(disableMapJoinWithHint(getQB().getParseInfo().getHintList()));

    if (forViewCreation && shouldComputeLineage(conf)) {
      // Generate lineage info if LineageLogger hook is configured.
      // Add the transformation that computes the lineage information.
      List<Transform> transformations = new ArrayList<Transform>();
      transformations.add(new HiveOpConverterPostProc());
      transformations.add(Generator.fromConf(conf));
      for (Transform t : transformations) {
        pCtx = t.transform(pCtx);
      }
    }
    perfLogger.perfLogEnd(this.getClass().getName(), PerfLogger.PARSE_CONTEXT_GENERATION);

    // 5. Take care of view creation
    perfLogger.perfLogBegin(this.getClass().getName(), PerfLogger.SAVE_AND_VALIDATE_VIEW);
    if (createVwDesc != null) {
      if (ctx.getExplainAnalyze() == AnalyzeState.RUNNING) {
        return;
      }

      if (!ctx.isCboSucceeded()) {
        saveViewDefinition();
      }

      // validate the create view statement at this point, the createVwDesc gets
      // all the information for semanticcheck
      validateCreateView();

      createVwDesc.setTablesUsed(pCtx.getTablesUsed());
    }
    perfLogger.perfLogEnd(this.getClass().getName(), PerfLogger.SAVE_AND_VALIDATE_VIEW);

    // If we're creating views and ColumnAccessInfo is already created, we should not run these, since
    // it means that in step 2, the ColumnAccessInfo was already created
    perfLogger.perfLogBegin(this.getClass().getName(), PerfLogger.LOGICAL_OPTIMIZATION);
    if (!forViewCreation ||  getColumnAccessInfo() == null) {
      // 6. Generate table access stats if required
      if (HiveConf.getBoolVar(this.conf, HiveConf.ConfVars.HIVE_STATS_COLLECT_TABLEKEYS)) {
        TableAccessAnalyzer tableAccessAnalyzer = new TableAccessAnalyzer(pCtx);
        setTableAccessInfo(tableAccessAnalyzer.analyzeTableAccess());
      }
      AuxOpTreeSignature.linkAuxSignatures(pCtx);
      // 7. Perform Logical optimization
      if (LOG.isDebugEnabled()) {
        LOG.debug("Before logical optimization\n" + Operator.toString(pCtx.getTopOps().values()));
      }
      Optimizer optm = new Optimizer();
      optm.setPctx(pCtx);
      optm.initialize(conf);
      pCtx = optm.optimize();
      if (pCtx.getColumnAccessInfo() != null) {
        // set ColumnAccessInfo for view column authorization
        setColumnAccessInfo(pCtx.getColumnAccessInfo());
      }
      if (LOG.isDebugEnabled()) {
        LOG.debug("After logical optimization\n" + Operator.toString(pCtx.getTopOps().values()));
      }

      // 8. Generate column access stats if required - wait until column pruning
      // takes place during optimization
      boolean isColumnInfoNeedForAuth = SessionState.get().isAuthorizationModeV2()
              && HiveConf.getBoolVar(conf, HiveConf.ConfVars.HIVE_AUTHORIZATION_ENABLED);
      if (isColumnInfoNeedForAuth
              || HiveConf.getBoolVar(this.conf, HiveConf.ConfVars.HIVE_STATS_COLLECT_SCANCOLS)) {
        ColumnAccessAnalyzer columnAccessAnalyzer = new ColumnAccessAnalyzer(pCtx);
        // view column access info is carried by this.getColumnAccessInfo().
        setColumnAccessInfo(columnAccessAnalyzer.analyzeColumnAccess(this.getColumnAccessInfo()));
      }
    }
    perfLogger.perfLogEnd(this.getClass().getName(), PerfLogger.LOGICAL_OPTIMIZATION);

    if (forViewCreation) {
      return;
    }

    // 9. Optimize Physical op tree & Translate to target execution engine (MR,
    // TEZ..)
    perfLogger.perfLogBegin(this.getClass().getName(), PerfLogger.PHYSICAL_OPTIMIZATION);
    compilePlan(pCtx);
    perfLogger.perfLogEnd(this.getClass().getName(), PerfLogger.PHYSICAL_OPTIMIZATION);

    //find all Acid FileSinkOperatorS
    perfLogger.perfLogBegin(this.getClass().getName(), PerfLogger.POST_PROCESSING);
    new QueryPlanPostProcessor(rootTasks, acidFileSinks, ctx.getExecutionId());

    // 10. Attach CTAS/Insert-Commit-hooks for Storage Handlers
    final Optional<TezTask> optionalTezTask =
        rootTasks.stream().filter(task -> task instanceof TezTask).map(task -> (TezTask) task)
            .findFirst();
    if (optionalTezTask.isPresent()) {
      final TezTask tezTask = optionalTezTask.get();
      rootTasks.stream()
          .filter(task -> task.getWork() instanceof DDLWork)
          .map(task -> (DDLWork) task.getWork())
          .filter(ddlWork -> ddlWork.getDDLDesc() instanceof PreInsertTableDesc)
          .map(ddlWork -> (PreInsertTableDesc)ddlWork.getDDLDesc())
          .map(desc -> new InsertCommitHookDesc(desc.getTable(), desc.isOverwrite()))
          .forEach(insertCommitHookDesc -> tezTask.addDependentTask(
              TaskFactory.get(new DDLWork(getInputs(), getOutputs(), insertCommitHookDesc), conf)));
    }

    LOG.info("Completed plan generation");

    // 11. put accessed columns to readEntity
    if (HiveConf.getBoolVar(this.conf, HiveConf.ConfVars.HIVE_STATS_COLLECT_SCANCOLS)) {
      putAccessedColumnsToReadEntity(inputs, columnAccessInfo);
    }

    if (isCacheEnabled && lookupInfo != null) {
      if (queryCanBeCached()) {
        // Last chance - check if the query is available in the cache.
        // Since we have already generated a query plan, using a cached query result at this point
        // requires SemanticAnalyzer state to be reset.
        if (checkResultsCache(lookupInfo, true)) {
          LOG.info("Cached result found on second lookup");
        } else {
          QueryResultsCache.QueryInfo queryInfo = createCacheQueryInfoForQuery(lookupInfo);

          // Specify that the results of this query can be cached.
          setCacheUsage(new CacheUsage(
              CacheUsage.CacheStatus.CAN_CACHE_QUERY_RESULTS, queryInfo));
        }
      }
    }
    perfLogger.perfLogEnd(this.getClass().getName(), PerfLogger.POST_PROCESSING);
  }
Planner specific stuff goes in here.
ql/src/java/org/apache/hadoop/hive/ql/parse/SemanticAnalyzer.java