public boolean processMVBasedQueryFix(StmtTableScan mvTableScan, Set<SchemaColumn> scanColumns, JoinNode joinTree,
            List<ParsedColInfo> displayColumns, List<ParsedColInfo> groupByColumns) {

        // Check valid cases first
        //@TODO
        if  ( ! (mvTableScan instanceof StmtTargetTableScan)) {
            return false;
        }
        Table table = ((StmtTargetTableScan)mvTableScan).getTargetTable();
        assert (table != null);
        String mvTableName = table.getTypeName();
        Table srcTable = table.getMaterializer();
        if (srcTable == null) {
            return false;
        }
        if (table.getIsreplicated()) {
            return false;
        }

        // Justify whether partition column is in group by column list or not
        if (table.getPartitioncolumn() != null) {
            return false;
        }

        m_mvTableScan = mvTableScan;

        Set<String> mvDDLGroupbyColumnNames = new HashSet<>();
        List<Column> mvColumnArray =
                CatalogUtil.getSortedCatalogItems(table.getColumns(), "index");

        String mvTableAlias = getMVTableAlias();

        // Get the number of group-by columns.
        int numOfGroupByColumns;
        MaterializedViewInfo mvInfo = srcTable.getViews().get(mvTableName);
        if (mvInfo != null) {
            // single table view
            String complexGroupbyJson = mvInfo.getGroupbyexpressionsjson();
            if (complexGroupbyJson.length() > 0) {
                List<AbstractExpression> mvComplexGroupbyCols = null;
                try {
                    mvComplexGroupbyCols = AbstractExpression.fromJSONArrayString(complexGroupbyJson, null);
                }
                catch (JSONException e) {
                    e.printStackTrace();
                }
                numOfGroupByColumns = mvComplexGroupbyCols.size();
            }
            else {
                numOfGroupByColumns = mvInfo.getGroupbycols().size();
            }
        }
        else {
            // joined table view
            MaterializedViewHandlerInfo mvHandlerInfo = table.getMvhandlerinfo().get("mvHandlerInfo");
            numOfGroupByColumns = mvHandlerInfo.getGroupbycolumncount();
        }

        if (scanColumns.isEmpty() && numOfGroupByColumns == 0) {
            // This is an edge case that can happen if the view
            // has no group by keys, and we are just
            // doing a count(*) on the output of the view.
            //
            // Having no GB keys or scan columns would cause us to
            // produce plan nodes that have a 0-column output schema.
            // We can't handle this in several places, so add the
            // count(*) column from the view to the scan columns.
            Column mvCol = mvColumnArray.get(0); // this is the "count(*)" column.
            TupleValueExpression tve = new TupleValueExpression(
                    mvTableName, mvTableAlias, mvCol, 0);
            tve.setOrigStmtId(mvTableScan.getStatementId());

            String colName = mvCol.getName();
            SchemaColumn scol = new SchemaColumn(mvTableName, mvTableAlias,
                    colName, colName, tve);
            scanColumns.add(scol);
        }

        // Start to do real materialized view processing to fix the duplicates problem.
        // (1) construct new projection columns for scan plan node.
        Set<SchemaColumn> mvDDLGroupbyColumns = new HashSet<>();
        NodeSchema inlineProjSchema = new NodeSchema();
        for (SchemaColumn scol: scanColumns) {
            inlineProjSchema.addColumn(scol);
        }


        for (int i = 0; i < numOfGroupByColumns; i++) {
            Column mvCol = mvColumnArray.get(i);
            String colName = mvCol.getName();

            TupleValueExpression tve = new TupleValueExpression(
                    mvTableName, mvTableAlias, mvCol, i);
            tve.setOrigStmtId(mvTableScan.getStatementId());

            mvDDLGroupbyColumnNames.add(colName);

            SchemaColumn scol = new SchemaColumn(mvTableName, mvTableAlias,
                    colName, colName, tve);
            mvDDLGroupbyColumns.add(scol);
            if (!scanColumns.contains(scol)) {
                scanColumns.add(scol);
                // construct new projection columns for scan plan node.
                inlineProjSchema.addColumn(scol);
            }
        }

        // Record the re-aggregation type for each scan columns.
        Map<String, ExpressionType> mvColumnReAggType = new HashMap<>();
        for (int i = numOfGroupByColumns; i < mvColumnArray.size(); i++) {
            Column mvCol = mvColumnArray.get(i);
            ExpressionType reAggType = ExpressionType.get(mvCol.getAggregatetype());

            if (reAggType == ExpressionType.AGGREGATE_COUNT_STAR ||
                    reAggType == ExpressionType.AGGREGATE_COUNT) {
                reAggType = ExpressionType.AGGREGATE_SUM;
            }
            mvColumnReAggType.put(mvCol.getName(), reAggType);
        }

        assert (inlineProjSchema.size() > 0);
        m_scanInlinedProjectionNode =
                new ProjectionPlanNode(inlineProjSchema);

        // (2) Construct the reAggregation Node.

        // Construct the reAggregation plan node's aggSchema
        m_reAggNode = new HashAggregatePlanNode();
        int outputColumnIndex = 0;
        // inlineProjSchema contains the group by columns, while aggSchema may do not.
        NodeSchema aggSchema = new NodeSchema();

        // Construct reAggregation node's aggregation and group by list.
        for (SchemaColumn scol: inlineProjSchema) {
            if (mvDDLGroupbyColumns.contains(scol)) {
                // Add group by expression.
                m_reAggNode.addGroupByExpression(scol.getExpression());
            }
            else {
                ExpressionType reAggType = mvColumnReAggType.get(scol.getColumnName());
                assert(reAggType != null);
                AbstractExpression agg_input_expr = scol.getExpression();
                assert(agg_input_expr instanceof TupleValueExpression);
                // Add aggregation information.
                m_reAggNode.addAggregate(reAggType, false, outputColumnIndex, agg_input_expr);
            }
            aggSchema.addColumn(scol);
            outputColumnIndex++;
        }

        assert (aggSchema.size() > 0);
        m_reAggNode.setOutputSchema(aggSchema);


        // Collect all TVEs that need to be do re-aggregation in coordinator.
        List<TupleValueExpression> needReAggTVEs = new ArrayList<>();
        List<AbstractExpression> aggPostExprs = new ArrayList<>();

        for (int i = numOfGroupByColumns; i < mvColumnArray.size(); i++) {
            Column mvCol = mvColumnArray.get(i);

            TupleValueExpression tve = new TupleValueExpression(
                    mvTableName, mvTableAlias, mvCol, -1);
            tve.setOrigStmtId(mvTableScan.getStatementId());

            needReAggTVEs.add(tve);
        }

        collectReAggNodePostExpressions(joinTree, needReAggTVEs, aggPostExprs);

        AbstractExpression aggPostExpr = ExpressionUtil.combinePredicates(aggPostExprs);
        // Add post filters for the reAggregation node.
        m_reAggNode.setPostPredicate(aggPostExpr);


        // ENG-5386
        if (m_edgeCaseQueryNoFixNeeded &&
                edgeCaseQueryNoFixNeeded(mvDDLGroupbyColumnNames, mvColumnReAggType, displayColumns, groupByColumns)) {
            return false;
        }

        m_needed = true;
        return true;
    }
public boolean processMVBasedQueryFix ( StmtTableScan mvTableScan , Set < SchemaColumn > scanColumns , JoinNode joinTree , List < ParsedColInfo > displayColumns , List < ParsedColInfo > groupByColumns ) { if ( ! ( mvTableScan instanceof StmtTargetTableScan ) ) { return false ; } Table table = ( ( StmtTargetTableScan ) mvTableScan ) . getTargetTable ( ) ; assert ( table != null ) ; String mvTableName = table . getTypeName ( ) ; Table srcTable = table . getMaterializer ( ) ; if ( srcTable == null ) { return false ; } if ( table . getIsreplicated ( ) ) { return false ; } if ( table . getPartitioncolumn ( ) != null ) { return false ; } m_mvTableScan = mvTableScan ; Set < String > mvDDLGroupbyColumnNames = new HashSet < > ( ) ; List < Column > mvColumnArray = CatalogUtil . getSortedCatalogItems ( table . getColumns ( ) , "index" ) ; String mvTableAlias = getMVTableAlias ( ) ; int numOfGroupByColumns ; MaterializedViewInfo mvInfo = srcTable . getViews ( ) . get ( mvTableName ) ; if ( mvInfo != null ) { String complexGroupbyJson = mvInfo . getGroupbyexpressionsjson ( ) ; if ( complexGroupbyJson . length ( ) > 0 ) { List < AbstractExpression > mvComplexGroupbyCols = null ; try { mvComplexGroupbyCols = AbstractExpression . fromJSONArrayString ( complexGroupbyJson , null ) ; } catch ( JSONException e ) { e . printStackTrace ( ) ; } numOfGroupByColumns = mvComplexGroupbyCols . size ( ) ; } else { numOfGroupByColumns = mvInfo . getGroupbycols ( ) . size ( ) ; } } else { MaterializedViewHandlerInfo mvHandlerInfo = table . getMvhandlerinfo ( ) . get ( "mvHandlerInfo" ) ; numOfGroupByColumns = mvHandlerInfo . getGroupbycolumncount ( ) ; } if ( scanColumns . isEmpty ( ) && numOfGroupByColumns == 0 ) { Column mvCol = mvColumnArray . get ( 0 ) ; TupleValueExpression tve = new TupleValueExpression ( mvTableName , mvTableAlias , mvCol , 0 ) ; tve . setOrigStmtId ( mvTableScan . getStatementId ( ) ) ; String colName = mvCol . getName ( ) ; SchemaColumn scol = new SchemaColumn ( mvTableName , mvTableAlias , colName , colName , tve ) ; scanColumns . add ( scol ) ; } Set < SchemaColumn > mvDDLGroupbyColumns = new HashSet < > ( ) ; NodeSchema inlineProjSchema = new NodeSchema ( ) ; for ( SchemaColumn scol : scanColumns ) { inlineProjSchema . addColumn ( scol ) ; } for ( int i = 0 ; i < numOfGroupByColumns ; i ++ ) { Column mvCol = mvColumnArray . get ( i ) ; String colName = mvCol . getName ( ) ; TupleValueExpression tve = new TupleValueExpression ( mvTableName , mvTableAlias , mvCol , i ) ; tve . setOrigStmtId ( mvTableScan . getStatementId ( ) ) ; mvDDLGroupbyColumnNames . add ( colName ) ; SchemaColumn scol = new SchemaColumn ( mvTableName , mvTableAlias , colName , colName , tve ) ; mvDDLGroupbyColumns . add ( scol ) ; if ( ! scanColumns . contains ( scol ) ) { scanColumns . add ( scol ) ; inlineProjSchema . addColumn ( scol ) ; } } Map < String , ExpressionType > mvColumnReAggType = new HashMap < > ( ) ; for ( int i = numOfGroupByColumns ; i < mvColumnArray . size ( ) ; i ++ ) { Column mvCol = mvColumnArray . get ( i ) ; ExpressionType reAggType = ExpressionType . get ( mvCol . getAggregatetype ( ) ) ; if ( reAggType == ExpressionType . AGGREGATE_COUNT_STAR || reAggType == ExpressionType . AGGREGATE_COUNT ) { reAggType = ExpressionType . AGGREGATE_SUM ; } mvColumnReAggType . put ( mvCol . getName ( ) , reAggType ) ; } assert ( inlineProjSchema . size ( ) > 0 ) ; m_scanInlinedProjectionNode = new ProjectionPlanNode ( inlineProjSchema ) ; m_reAggNode = new HashAggregatePlanNode ( ) ; int outputColumnIndex = 0 ; NodeSchema aggSchema = new NodeSchema ( ) ; for ( SchemaColumn scol : inlineProjSchema ) { if ( mvDDLGroupbyColumns . contains ( scol ) ) { m_reAggNode . addGroupByExpression ( scol . getExpression ( ) ) ; } else { ExpressionType reAggType = mvColumnReAggType . get ( scol . getColumnName ( ) ) ; assert ( reAggType != null ) ; AbstractExpression agg_input_expr = scol . getExpression ( ) ; assert ( agg_input_expr instanceof TupleValueExpression ) ; m_reAggNode . addAggregate ( reAggType , false , outputColumnIndex , agg_input_expr ) ; } aggSchema . addColumn ( scol ) ; outputColumnIndex ++ ; } assert ( aggSchema . size ( ) > 0 ) ; m_reAggNode . setOutputSchema ( aggSchema ) ; List < TupleValueExpression > needReAggTVEs = new ArrayList < > ( ) ; List < AbstractExpression > aggPostExprs = new ArrayList < > ( ) ; for ( int i = numOfGroupByColumns ; i < mvColumnArray . size ( ) ; i ++ ) { Column mvCol = mvColumnArray . get ( i ) ; TupleValueExpression tve = new TupleValueExpression ( mvTableName , mvTableAlias , mvCol , - 1 ) ; tve . setOrigStmtId ( mvTableScan . getStatementId ( ) ) ; needReAggTVEs . add ( tve ) ; } collectReAggNodePostExpressions ( joinTree , needReAggTVEs , aggPostExprs ) ; AbstractExpression aggPostExpr = ExpressionUtil . combinePredicates ( aggPostExprs ) ; m_reAggNode . setPostPredicate ( aggPostExpr ) ; if ( m_edgeCaseQueryNoFixNeeded && edgeCaseQueryNoFixNeeded ( mvDDLGroupbyColumnNames , mvColumnReAggType , displayColumns , groupByColumns ) ) { return false ; } m_needed = true ; return true ; }
Check whether the results from a materialized view need to be
re-aggregated on the coordinator by the view's GROUP BY columns
prior to any of the processing specified by the query.
This is normally the case when a mat view's source table is partitioned
and the view's GROUP BY does not include the partition key.
There is a special edge case where the query already contains the exact
reaggregations that the added-cost fix would introduce, so the fix can
be skipped as an optimization.
Set the m_needed flag to true, only if the reaggregation fix is needed.
@return The value of m_needed