Search in sources :

Example 1 with Converter

use of org.apache.calcite.rel.convert.Converter in project calcite by apache.

the class VolcanoPlanner method registerImpl.

/**
 * Registers a new expression <code>exp</code> and queues up rule matches.
 * If <code>set</code> is not null, makes the expression part of that
 * equivalence set. If an identical expression is already registered, we
 * don't need to register this one and nor should we queue up rule matches.
 *
 * @param rel relational expression to register. Must be either a
 *         {@link RelSubset}, or an unregistered {@link RelNode}
 * @param set set that rel belongs to, or <code>null</code>
 * @return the equivalence-set
 */
private RelSubset registerImpl(RelNode rel, RelSet set) {
    if (rel instanceof RelSubset) {
        return registerSubset(set, (RelSubset) rel);
    }
    assert !isRegistered(rel) : "already been registered: " + rel;
    if (rel.getCluster().getPlanner() != this) {
        throw new AssertionError("Relational expression " + rel + " belongs to a different planner than is currently being used.");
    }
    // Now is a good time to ensure that the relational expression
    // implements the interface required by its calling convention.
    final RelTraitSet traits = rel.getTraitSet();
    final Convention convention = traits.getTrait(ConventionTraitDef.INSTANCE);
    assert convention != null;
    if (!convention.getInterface().isInstance(rel) && !(rel instanceof Converter)) {
        throw new AssertionError("Relational expression " + rel + " has calling-convention " + convention + " but does not implement the required interface '" + convention.getInterface() + "' of that convention");
    }
    if (traits.size() != traitDefs.size()) {
        throw new AssertionError("Relational expression " + rel + " does not have the correct number of traits: " + traits.size() + " != " + traitDefs.size());
    }
    // Ensure that its sub-expressions are registered.
    rel = rel.onRegister(this);
    // Record its provenance. (Rule call may be null.)
    if (ruleCallStack.isEmpty()) {
        provenanceMap.put(rel, Provenance.EMPTY);
    } else {
        final VolcanoRuleCall ruleCall = ruleCallStack.peek();
        provenanceMap.put(rel, new RuleProvenance(ruleCall.rule, ImmutableList.copyOf(ruleCall.rels), ruleCall.id));
    }
    // If it is equivalent to an existing expression, return the set that
    // the equivalent expression belongs to.
    Pair<String, RelDataType> key = key(rel);
    RelNode equivExp = mapDigestToRel.get(key);
    if (equivExp == null) {
    // do nothing
    } else if (equivExp == rel) {
        return getSubset(rel);
    } else {
        assert RelOptUtil.equal("left", equivExp.getRowType(), "right", rel.getRowType(), Litmus.THROW);
        RelSet equivSet = getSet(equivExp);
        if (equivSet != null) {
            LOGGER.trace("Register: rel#{} is equivalent to {}", rel.getId(), equivExp.getDescription());
            return registerSubset(set, getSubset(equivExp));
        }
    }
    // Converters are in the same set as their children.
    if (rel instanceof Converter) {
        final RelNode input = ((Converter) rel).getInput();
        final RelSet childSet = getSet(input);
        if ((set != null) && (set != childSet) && (set.equivalentSet == null)) {
            LOGGER.trace("Register #{} {} (and merge sets, because it is a conversion)", rel.getId(), rel.getDigest());
            merge(set, childSet);
            registerCount++;
            // expression.
            if (fixUpInputs(rel)) {
                rel.recomputeDigest();
                key = key(rel);
                RelNode equivRel = mapDigestToRel.get(key);
                if ((equivRel != rel) && (equivRel != null)) {
                    // make sure this bad rel didn't get into the
                    // set in any way (fixupInputs will do this but it
                    // doesn't know if it should so it does it anyway)
                    set.obliterateRelNode(rel);
                    // one, and forget about this one.
                    return getSubset(equivRel);
                }
            }
        } else {
            set = childSet;
        }
    }
    // Place the expression in the appropriate equivalence set.
    if (set == null) {
        set = new RelSet(nextSetId++, Util.minus(RelOptUtil.getVariablesSet(rel), rel.getVariablesSet()), RelOptUtil.getVariablesUsed(rel));
        this.allSets.add(set);
    }
    // merging at the same time.
    while (set.equivalentSet != null) {
        set = set.equivalentSet;
    }
    // Allow each rel to register its own rules.
    registerClass(rel);
    registerCount++;
    final int subsetBeforeCount = set.subsets.size();
    RelSubset subset = addRelToSet(rel, set);
    final RelNode xx = mapDigestToRel.put(key, rel);
    assert xx == null || xx == rel : rel.getDigest();
    LOGGER.trace("Register {} in {}", rel.getDescription(), subset.getDescription());
    // recursively registered its children. If this is the case, we're done.
    if (xx != null) {
        return subset;
    }
    // important.
    if (rel == this.root) {
        ruleQueue.subsetImportances.put(subset, // todo: remove
        1.0);
    }
    for (RelNode input : rel.getInputs()) {
        RelSubset childSubset = (RelSubset) input;
        childSubset.set.parents.add(rel);
        // Child subset is more important now a new parent uses it.
        ruleQueue.recompute(childSubset);
    }
    if (rel == this.root) {
        ruleQueue.subsetImportances.remove(subset);
    }
    // Remember abstract converters until they're satisfied
    if (rel instanceof AbstractConverter) {
        set.abstractConverters.add((AbstractConverter) rel);
    }
    // If this set has any unsatisfied converters, try to satisfy them.
    checkForSatisfiedConverters(set, rel);
    // Make sure this rel's subset importance is updated
    ruleQueue.recompute(subset, true);
    // Queue up all rules triggered by this relexp's creation.
    fireRules(rel, true);
    // It's a new subset.
    if (set.subsets.size() > subsetBeforeCount) {
        fireRules(subset, true);
    }
    return subset;
}
Also used : RelDataType(org.apache.calcite.rel.type.RelDataType) RelTraitSet(org.apache.calcite.plan.RelTraitSet) Convention(org.apache.calcite.plan.Convention) RelNode(org.apache.calcite.rel.RelNode) Converter(org.apache.calcite.rel.convert.Converter)

Example 2 with Converter

use of org.apache.calcite.rel.convert.Converter in project calcite by apache.

the class HepPlanner method doesConverterApply.

private boolean doesConverterApply(ConverterRule converterRule, HepRelVertex vertex) {
    RelTrait outTrait = converterRule.getOutTrait();
    List<HepRelVertex> parents = Graphs.predecessorListOf(graph, vertex);
    for (HepRelVertex parent : parents) {
        RelNode parentRel = parent.getCurrentRel();
        if (parentRel instanceof Converter) {
            // We don't support converter chains.
            continue;
        }
        if (parentRel.getTraitSet().contains(outTrait)) {
            // This parent wants the traits produced by the converter.
            return true;
        }
    }
    return (vertex == root) && (requestedRootTraits != null) && requestedRootTraits.contains(outTrait);
}
Also used : RelTrait(org.apache.calcite.plan.RelTrait) RelNode(org.apache.calcite.rel.RelNode) Converter(org.apache.calcite.rel.convert.Converter)

Example 3 with Converter

use of org.apache.calcite.rel.convert.Converter in project calcite by apache.

the class HepPlanner method applyTransformationResults.

private HepRelVertex applyTransformationResults(HepRelVertex vertex, HepRuleCall call, RelTrait parentTrait) {
    assert !call.getResults().isEmpty();
    RelNode bestRel = null;
    if (call.getResults().size() == 1) {
        // No costing required; skip it to minimize the chance of hitting
        // rels without cost information.
        bestRel = call.getResults().get(0);
    } else {
        RelOptCost bestCost = null;
        final RelMetadataQuery mq = call.getMetadataQuery();
        for (RelNode rel : call.getResults()) {
            RelOptCost thisCost = getCost(rel, mq);
            if (LOGGER.isTraceEnabled()) {
                // Keep in the isTraceEnabled for the getRowCount method call
                LOGGER.trace("considering {} with cumulative cost={} and rowcount={}", rel, thisCost, mq.getRowCount(rel));
            }
            if ((bestRel == null) || thisCost.isLt(bestCost)) {
                bestRel = rel;
                bestCost = thisCost;
            }
        }
    }
    ++nTransformations;
    notifyTransformation(call, bestRel, true);
    // Before we add the result, make a copy of the list of vertex's
    // parents.  We'll need this later during contraction so that
    // we only update the existing parents, not the new parents
    // (otherwise loops can result).  Also take care of filtering
    // out parents by traits in case we're dealing with a converter rule.
    final List<HepRelVertex> allParents = Graphs.predecessorListOf(graph, vertex);
    final List<HepRelVertex> parents = new ArrayList<>();
    for (HepRelVertex parent : allParents) {
        if (parentTrait != null) {
            RelNode parentRel = parent.getCurrentRel();
            if (parentRel instanceof Converter) {
                // the multi-parent DAG case.
                continue;
            }
            if (!parentRel.getTraitSet().contains(parentTrait)) {
                // This parent does not want the converted result.
                continue;
            }
        }
        parents.add(parent);
    }
    HepRelVertex newVertex = addRelToGraph(bestRel);
    // There's a chance that newVertex is the same as one
    // of the parents due to common subexpression recognition
    // (e.g. the LogicalProject added by JoinCommuteRule).  In that
    // case, treat the transformation as a nop to avoid
    // creating a loop.
    int iParentMatch = parents.indexOf(newVertex);
    if (iParentMatch != -1) {
        newVertex = parents.get(iParentMatch);
    } else {
        contractVertices(newVertex, vertex, parents);
    }
    if (getListener() != null) {
        // Assume listener doesn't want to see garbage.
        collectGarbage();
    }
    notifyTransformation(call, bestRel, false);
    dumpGraph();
    return newVertex;
}
Also used : RelMetadataQuery(org.apache.calcite.rel.metadata.RelMetadataQuery) RelNode(org.apache.calcite.rel.RelNode) RelOptCost(org.apache.calcite.plan.RelOptCost) ArrayList(java.util.ArrayList) Converter(org.apache.calcite.rel.convert.Converter)

Aggregations

RelNode (org.apache.calcite.rel.RelNode)3 Converter (org.apache.calcite.rel.convert.Converter)3 ArrayList (java.util.ArrayList)1 Convention (org.apache.calcite.plan.Convention)1 RelOptCost (org.apache.calcite.plan.RelOptCost)1 RelTrait (org.apache.calcite.plan.RelTrait)1 RelTraitSet (org.apache.calcite.plan.RelTraitSet)1 RelMetadataQuery (org.apache.calcite.rel.metadata.RelMetadataQuery)1 RelDataType (org.apache.calcite.rel.type.RelDataType)1