public boolean rewritePre()

in asterixdb/asterix-algebra/src/main/java/org/apache/asterix/optimizer/rules/cbo/EnumerateJoinsRule.java [130:370]


    public boolean rewritePre(Mutable<ILogicalOperator> opRef, IOptimizationContext context)
            throws AlgebricksException {

        boolean cboMode = this.getCBOMode(context);
        boolean cboTestMode = this.getCBOTestMode(context);

        if (!(cboMode || cboTestMode)) {
            return false;
        }

        // If we reach here, then either cboMode or cboTestMode is true.
        // If cboTestMode is true, then we use predefined cardinalities for datasets for asterixdb regression tests.
        // If cboMode is true, then all datasets need to have samples, otherwise the check in doAllDataSourcesHaveSamples()
        // further below will return false.
        ILogicalOperator op = opRef.getValue();
        if (!(joinClause(op) || ((op.getOperatorTag() == LogicalOperatorTag.DISTRIBUTE_RESULT)))) {
            return false;
        }

        if (op.getOperatorTag() == LogicalOperatorTag.DISTRIBUTE_RESULT) {
            // If cboMode or cboTestMode is true, identify each DistinctOp or GroupByOp for the corresponding DataScanOp
            getDistinctOpsForJoinNodes(op, context);

            // Find the order by op, so we can annotate cost/cards
            findOrderByOp(op);

            // Find the topmost assign, so we can find all the final projected variables.
            ILogicalOperator tmp = op;

            while (tmp.getOperatorTag() != LogicalOperatorTag.EMPTYTUPLESOURCE) {
                if (tmp.getOperatorTag().equals(LogicalOperatorTag.ASSIGN)) {
                    addAllAssignExprVars(resultAndJoinVars, (AssignOperator) tmp);
                    break;
                }
                tmp = tmp.getInputs().get(0).getValue();
            }
        }

        // if this join has already been seen before, no need to apply the rule again
        if (context.checkIfInDontApplySet(this, op)) {
            return false;
        }

        IPlanPrettyPrinter pp = context.getPrettyPrinter();

        String viewInPlan;
        if (LOGGER.isTraceEnabled()) {
            viewInPlan = new ALogicalPlanImpl(opRef).toString(); //useful when debugging
        }
        printPlan(pp, (AbstractLogicalOperator) op, "Original Whole plan1");

        int phase = 1;
        init(phase);
        boolean canTransform = getJoinOpsAndLeafInputs(null, op, -1, phase);

        if (!canTransform) {
            return cleanUp();
        }

        if (everyLeafInputDoesNotHaveADataScanOperator(leafInputs)) {
            return cleanUp();
        }
        if (LOGGER.isTraceEnabled()) {
            viewInPlan = new ALogicalPlanImpl(opRef).toString(); //useful when debugging
        }
        if (arrayUnnestPossible) {
            joinEnum.stats = new Stats(context, joinEnum);
            if (cboMode) {
                if (!doAllDataSourcesHaveSamples(leafInputs, context)) {
                    return cleanUp();
                }
            }
            // Here on, we expect that changes can be made to the incoming plan and that optimization will proceed
            // without any hitch. Basically, we cannot go back now!!
            // now that we know it is safe to proceed with unnesting array optimization, we will remove
            // the unnestOps and related assign ops from the leafInputs and add them back later at the right places.
            //select count (*) from KS1 x, x.uarr_i, x.zarr_i, KS2 y, y. earr_i where x.rand_n = y.rand_n;
            //realInput 0 = true      (KS1)
            //realInput 1 = false
            //realInput 2 = false
            //realInput 3 = true (KS2)
            //realInput 4 = false
            //Note: The Unnesting code may move UNNEST Ops from the leafInputs higher up in the plan.
            //The code is not designed to deal with UNNEST Ops that are not in the leafInputs.
            int i = -1;
            int j = -1;
            for (List<List<ILogicalOperator>> l : unnestOpsInfo) {
                i++;
                if (realLeafInputs.get(i)) {
                    j++;
                    removeUnnestOpsFromLeafInputLevel1(leafInputs.get(j), l);
                }
            }

            // now the plan should have no unnestOps and no related assigns
            if (LOGGER.isTraceEnabled()) {
                String viewOldPlan = new ALogicalPlanImpl(opRef).toString(); //useful when debugging
            }
            introduceFakeOuterJoins(opRef, context);
            if (LOGGER.isTraceEnabled()) {
                String viewNewPlan = new ALogicalPlanImpl(opRef).toString(); //useful when debugging
            }
            phase = 2;
            init(phase);
            getJoinOpsAndLeafInputs(null, op, -1, phase);
        } else {
            unnestOpsInfo.clear();
        }

        collectJoinConditionsVariables(); // will be used for determining which variables will be projected from the base levels

        convertOuterJoinstoJoinsIfPossible(outerJoinsDependencyList);

        printPlan(pp, (AbstractLogicalOperator) op, "Original Whole plan2");
        numberOfFromTerms = leafInputs.size();

        if (LOGGER.isTraceEnabled()) {
            viewInPlan = new ALogicalPlanImpl(opRef).toString(); //useful when debugging
            LOGGER.trace("viewInPlan");
            LOGGER.trace(viewInPlan);
        }

        if (buildSets.size() > 1) {
            buildSets.sort(Comparator.comparingDouble(o -> o.second)); // sort on the number of tables in each set
            // we need to build the smaller sets first. So we need to find these first.
        }
        joinEnum.initEnum((AbstractLogicalOperator) op, cboMode, cboTestMode, numberOfFromTerms, leafInputs, allJoinOps,
                assignOps, outerJoinsDependencyList, buildSets, varLeafInputIds, unnestOpsInfo,
                dataScanAndGroupByDistinctOps, rootGroupByDistinctOp, rootOrderByOp, resultAndJoinVars,
                fakeLeafInputsMap, context);

        if (cboMode) {
            if (!doAllDataSourcesHaveSamples(leafInputs, context)) {
                return cleanUp();
            }
        }
        if (LOGGER.isTraceEnabled()) {
            viewInPlan = new ALogicalPlanImpl(opRef).toString(); //useful when debugging
        }

        printLeafPlans(pp, leafInputs, "Inputs1");

        if (assignOps.size() > 0) {
            pushAssignsIntoLeafInputs(pp, leafInputs, assignOps, assignJoinExprs);
        }

        if (LOGGER.isTraceEnabled()) {
            viewInPlan = new ALogicalPlanImpl(opRef).toString(); //useful when debugging
        }
        printLeafPlans(pp, leafInputs, "Inputs2");
        if (LOGGER.isTraceEnabled()) {
            String viewPlan = new ALogicalPlanImpl(opRef).toString(); //useful when debugging
        }
        int cheapestPlan = joinEnum.enumerateJoins(); // MAIN CALL INTO CBO
        if (cheapestPlan == PlanNode.NO_PLAN) {
            return cleanUp();
        }

        PlanNode cheapestPlanNode = joinEnum.allPlans.get(cheapestPlan);

        generateHintWarnings();
        ILogicalOperator root = op;
        if (numberOfFromTerms > 1) {
            getNewJoinOps(cheapestPlanNode, allJoinOps);
            if (allJoinOps.size() != newJoinOps.size()) {
                return cleanUp(); // there are some cases such as R OJ S on true. Here there is an OJ predicate but the code in findJoinConditions
                // in JoinEnum does not capture this. Will fix later. Just bail for now.
            }
            if (LOGGER.isTraceEnabled()) {
                String viewInPlan2 = new ALogicalPlanImpl(opRef).toString(); //useful when debugging
            }
            buildNewTree(cheapestPlanNode, newJoinOps, new MutableInt(0), context);
            root = newJoinOps.get(0);
            if (LOGGER.isTraceEnabled()) {
                String viewInPlan2 = new ALogicalPlanImpl(new MutableObject<>(root)).toString();
            }
            if (phase == 2) {
                // Now remove the Fake outer joins and put in the original Unnest Ops along with the corresponding Assign Ops
                modifyUnnestInfo = new ArrayList<>();
                collectUnnestModificationInfo(null, root, cheapestPlanNode);
                for (int k = 0; k < modifyUnnestInfo.size(); k++) {
                    modifyTree(null, root, k);
                    if (newRootAfterUnnest != null) {
                        root = newRootAfterUnnest;
                    }
                }
                Mutable<ILogicalOperator> rootRef = new MutableObject<>(root);
                if (LOGGER.isTraceEnabled()) {
                    String viewInPlan2 = new ALogicalPlanImpl(rootRef).toString(); //useful when debugging
                }
            }
            opRef.setValue(root);
            if (LOGGER.isTraceEnabled()) {
                String viewInPlan2 = new ALogicalPlanImpl(opRef).toString(); //useful when debugging
            }
            context.computeAndSetTypeEnvironmentForOperator(root);

            if (assignOps.size() > 0) {
                for (int i = assignOps.size() - 1; i >= 0; i--) {
                    MutableBoolean removed = new MutableBoolean(false);
                    removed.setFalse();
                    pushAssignsAboveJoins(root, assignOps.get(i), assignJoinExprs.get(i), removed);
                    context.computeAndSetTypeEnvironmentForOperator(assignOps.get(i));
                    if (removed.isTrue()) {
                        assignOps.remove(i);
                    }
                }
            }

            printPlan(pp, (AbstractLogicalOperator) root, "New Whole Plan after buildNewTree 1");
            root = addRemainingAssignsAtTheTop(root, assignOps);
            printPlan(pp, (AbstractLogicalOperator) root, "New Whole Plan after buildNewTree 2");
            printPlan(pp, (AbstractLogicalOperator) root, "New Whole Plan after buildNewTree");

            // this will be the new root
            opRef.setValue(root);

            if (LOGGER.isTraceEnabled()) {
                String viewOutPlan = new ALogicalPlanImpl(opRef).toString(); //useful when debugging
                LOGGER.trace("viewOutPlan");
                LOGGER.trace(viewOutPlan);
            }

            if (LOGGER.isTraceEnabled()) {
                LOGGER.trace("---------------------------- Printing Leaf Inputs");
                printLeafPlans(pp, leafInputs, "Inputs");
                printPlan(pp, (AbstractLogicalOperator) root, "New Whole Plan");
            }
            // turn of this rule for all joins in this set (subtree)
            for (ILogicalOperator joinOp : newJoinOps) {
                context.addToDontApplySet(this, joinOp);
            }
        } else {
            buildNewTree(cheapestPlanNode);
        }
        context.computeAndSetTypeEnvironmentForOperator(root);
        if (LOGGER.isTraceEnabled()) {
            String finalPlan = new ALogicalPlanImpl(opRef).toString(); //useful when debugging
        }
        return true;
    }