blob: 21f6586cc2fade9411cd7806ffc6e0f2b967f2fd [file] [log] [blame]
/*
* 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.calcite.rel;
import org.apache.calcite.plan.Convention;
import org.apache.calcite.plan.RelDigest;
import org.apache.calcite.plan.RelOptCost;
import org.apache.calcite.plan.RelOptNode;
import org.apache.calcite.plan.RelOptPlanner;
import org.apache.calcite.plan.RelOptTable;
import org.apache.calcite.plan.RelOptUtil;
import org.apache.calcite.plan.RelTraitSet;
import org.apache.calcite.rel.core.CorrelationId;
import org.apache.calcite.rel.metadata.Metadata;
import org.apache.calcite.rel.metadata.RelMetadataQuery;
import org.apache.calcite.rel.type.RelDataType;
import org.apache.calcite.rex.RexNode;
import org.apache.calcite.rex.RexShuttle;
import org.apache.calcite.util.Litmus;
import org.apiguardian.api.API;
import org.checkerframework.checker.nullness.qual.EnsuresNonNullIf;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.checkerframework.dataflow.qual.Pure;
import java.util.List;
import java.util.Set;
/**
* A <code>RelNode</code> is a relational expression.
*
* <p>Relational expressions process data, so their names are typically verbs:
* Sort, Join, Project, Filter, Scan, Sample.
*
* <p>A relational expression is not a scalar expression; see
* {@link org.apache.calcite.sql.SqlNode} and {@link RexNode}.</p>
*
* <p>If this type of relational expression has some particular planner rules,
* it should implement the <em>public static</em> method
* {@link AbstractRelNode#register}.</p>
*
* <p>When a relational expression comes to be implemented, the system allocates
* a {@link org.apache.calcite.plan.RelImplementor} to manage the process. Every
* implementable relational expression has a {@link RelTraitSet} describing its
* physical attributes. The RelTraitSet always contains a {@link Convention}
* describing how the expression passes data to its consuming
* relational expression, but may contain other traits, including some applied
* externally. Because traits can be applied externally, implementations of
* RelNode should never assume the size or contents of their trait set (beyond
* those traits configured by the RelNode itself).</p>
*
* <p>For each calling-convention, there is a corresponding sub-interface of
* RelNode. For example,
* {@code org.apache.calcite.adapter.enumerable.EnumerableRel}
* has operations to manage the conversion to a graph of
* {@code org.apache.calcite.adapter.enumerable.EnumerableConvention}
* calling-convention, and it interacts with a
* {@code EnumerableRelImplementor}.</p>
*
* <p>A relational expression is only required to implement its
* calling-convention's interface when it is actually implemented, that is,
* converted into a plan/program. This means that relational expressions which
* cannot be implemented, such as converters, are not required to implement
* their convention's interface.</p>
*
* <p>Every relational expression must derive from {@link AbstractRelNode}. (Why
* have the <code>RelNode</code> interface, then? We need a root interface,
* because an interface can only derive from an interface.)</p>
*/
public interface RelNode extends RelOptNode, Cloneable {
//~ Methods ----------------------------------------------------------------
/**
* Return the CallingConvention trait from this RelNode's
* {@link #getTraitSet() trait set}.
*
* @return this RelNode's CallingConvention
*/
@Pure
@Nullable Convention getConvention();
/**
* Returns the name of the variable which is to be implicitly set at runtime
* each time a row is returned from the first input of this relational
* expression; or null if there is no variable.
*
* @return Name of correlating variable, or null
*/
@Nullable String getCorrelVariable();
/**
* Returns the <code>i</code><sup>th</sup> input relational expression.
*
* @param i Ordinal of input
* @return <code>i</code><sup>th</sup> input
*/
RelNode getInput(int i);
/**
* Returns the type of the rows returned by this relational expression.
*/
@Override RelDataType getRowType();
/**
* Returns the type of the rows expected for an input. Defaults to
* {@link #getRowType}.
*
* @param ordinalInParent input's 0-based ordinal with respect to this
* parent rel
* @return expected row type
*/
RelDataType getExpectedInputRowType(int ordinalInParent);
/**
* Returns an array of this relational expression's inputs. If there are no
* inputs, returns an empty list, not {@code null}.
*
* @return Array of this relational expression's inputs
*/
@Override List<RelNode> getInputs();
/**
* Returns an estimate of the number of rows this relational expression will
* return.
*
* <p>NOTE jvs 29-Mar-2006: Don't call this method directly. Instead, use
* {@link RelMetadataQuery#getRowCount}, which gives plugins a chance to
* override the rel's default ideas about row count.
*
* @param mq Metadata query
* @return Estimate of the number of rows this relational expression will
* return
*/
double estimateRowCount(RelMetadataQuery mq);
/**
* Returns the variables that are set in this relational
* expression but also used and therefore not available to parents of this
* relational expression.
*
* <p>Note: only {@link org.apache.calcite.rel.core.Correlate} should set
* variables.
*
* @return Names of variables which are set in this relational
* expression
*/
Set<CorrelationId> getVariablesSet();
/**
* Collects variables known to be used by this expression or its
* descendants. By default, no such information is available and must be
* derived by analyzing sub-expressions, but some optimizer implementations
* may insert special expressions which remember such information.
*
* @param variableSet receives variables used
*/
void collectVariablesUsed(Set<CorrelationId> variableSet);
/**
* Collects variables set by this expression.
* TODO: is this required?
*
* @param variableSet receives variables known to be set by
*/
void collectVariablesSet(Set<CorrelationId> variableSet);
/**
* Interacts with the {@link RelVisitor} in a
* {@link org.apache.calcite.util.Glossary#VISITOR_PATTERN visitor pattern} to
* traverse the tree of relational expressions.
*
* @param visitor Visitor that will traverse the tree of relational
* expressions
*/
void childrenAccept(RelVisitor visitor);
/**
* Returns the cost of this plan (not including children). The base
* implementation throws an error; derived classes should override.
*
* <p>NOTE jvs 29-Mar-2006: Don't call this method directly. Instead, use
* {@link RelMetadataQuery#getNonCumulativeCost}, which gives plugins a
* chance to override the rel's default ideas about cost.
*
* @param planner Planner for cost calculation
* @param mq Metadata query
* @return Cost of this plan (not including children)
*/
@Nullable RelOptCost computeSelfCost(RelOptPlanner planner, RelMetadataQuery mq);
/**
* Returns a metadata interface.
*
* @deprecated Use {@link RelMetadataQuery} via {@link #getCluster()}.
*
* @param <M> Type of metadata being requested
* @param metadataClass Metadata interface
* @param mq Metadata query
*
* @return Metadata object that supplies the desired metadata (never null,
* although if the information is not present the metadata object may
* return null from all methods)
*/
@Deprecated // to be removed before 2.0
<@Nullable M extends @Nullable Metadata> M metadata(Class<M> metadataClass, RelMetadataQuery mq);
/**
* Describes the inputs and attributes of this relational expression.
* Each node should call {@code super.explain}, then call the
* {@link org.apache.calcite.rel.externalize.RelWriterImpl#input(String, RelNode)}
* and
* {@link RelWriter#item(String, Object)}
* methods for each input and attribute.
*
* @param pw Plan writer
*/
void explain(RelWriter pw);
/**
* Returns a relational expression string of this {@code RelNode}.
* The string returned is the same as
* {@link RelOptUtil#toString(org.apache.calcite.rel.RelNode)}.
*
* This method is intended mainly for use while debugging in an IDE,
* as a convenient short-hand for RelOptUtil.toString.
* We recommend that classes implementing this interface
* do not override this method.
*
* @return Relational expression string of this {@code RelNode}
*/
default String explain() {
return RelOptUtil.toString(this);
}
/**
* Receives notification that this expression is about to be registered. The
* implementation of this method must at least register all child
* expressions.
*
* @param planner Planner that plans this relational node
* @return Relational expression that should be used by the planner
*/
RelNode onRegister(RelOptPlanner planner);
/**
* Returns a digest string of this {@code RelNode}.
*
* <p>Each call creates a new digest string,
* so don't forget to cache the result if necessary.
*
* @return Digest string of this {@code RelNode}
*
* @see #getRelDigest()
*/
@Override default String getDigest() {
return getRelDigest().toString();
}
/**
* Returns a digest of this {@code RelNode}.
*
* <p>INTERNAL USE ONLY. For use by the planner.
*
* @return Digest of this {@code RelNode}
* @see #getDigest()
*/
@API(since = "1.24", status = API.Status.INTERNAL)
RelDigest getRelDigest();
/**
* Recomputes the digest.
*
* <p>INTERNAL USE ONLY. For use by the planner.
*
* @see #getDigest()
*/
@API(since = "1.24", status = API.Status.INTERNAL)
void recomputeDigest();
/**
* Deep equality check for RelNode digest.
*
* <p>By default this method collects digest attributes from
* explain terms, then compares each attribute pair.</p>
*
* @return Whether the 2 RelNodes are equivalent or have the same digest.
* @see #deepHashCode()
*/
@EnsuresNonNullIf(expression = "#1", result = true)
boolean deepEquals(@Nullable Object obj);
/**
* Compute deep hash code for RelNode digest.
*
* @see #deepEquals(Object)
*/
int deepHashCode();
/**
* Replaces the <code>ordinalInParent</code><sup>th</sup> input. You must
* override this method if you override {@link #getInputs}.
*
* @param ordinalInParent Position of the child input, 0 is the first
* @param p New node that should be put at position {@code ordinalInParent}
*/
void replaceInput(
int ordinalInParent,
RelNode p);
/**
* If this relational expression represents an access to a table, returns
* that table, otherwise returns null.
*
* @return If this relational expression represents an access to a table,
* returns that table, otherwise returns null
*/
@Nullable RelOptTable getTable();
/**
* Returns the name of this relational expression's class, sans package
* name, for use in explain. For example, for a <code>
* org.apache.calcite.rel.ArrayRel.ArrayReader</code>, this method returns
* "ArrayReader".
*
* @return Name of this relational expression's class, sans package name,
* for use in explain
*/
String getRelTypeName();
/**
* Returns whether this relational expression is valid.
*
* <p>If assertions are enabled, this method is typically called with <code>
* litmus</code> = <code>THROW</code>, as follows:
*
* <blockquote>
* <pre>assert rel.isValid(Litmus.THROW)</pre>
* </blockquote>
*
* <p>This signals that the method can throw an {@link AssertionError} if it
* is not valid.
*
* @param litmus What to do if invalid
* @param context Context for validity checking
* @return Whether relational expression is valid
* @throws AssertionError if this relational expression is invalid and
* litmus is THROW
*/
boolean isValid(Litmus litmus, @Nullable Context context);
/**
* Creates a copy of this relational expression, perhaps changing traits and
* inputs.
*
* <p>Sub-classes with other important attributes are encouraged to create
* variants of this method with more parameters.
*
* @param traitSet Trait set
* @param inputs Inputs
* @return Copy of this relational expression, substituting traits and
* inputs
*/
RelNode copy(
RelTraitSet traitSet,
List<RelNode> inputs);
/**
* Registers any special rules specific to this kind of relational
* expression.
*
* <p>The planner calls this method this first time that it sees a
* relational expression of this class. The derived class should call
* {@link org.apache.calcite.plan.RelOptPlanner#addRule} for each rule, and
* then call {@code super.register}.</p>
*
* @param planner Planner to be used to register additional relational
* expressions
*/
void register(RelOptPlanner planner);
/**
* Indicates whether it is an enforcer operator, e.g. PhysicalSort,
* PhysicalHashDistribute, etc. As an enforcer, the operator must be
* created only when required traitSet is not satisfied by its input.
*
* @return Whether it is an enforcer operator
*/
default boolean isEnforcer() {
return false;
}
/**
* Accepts a visit from a shuttle.
*
* @param shuttle Shuttle
* @return A copy of this node incorporating changes made by the shuttle to
* this node's children
*/
RelNode accept(RelShuttle shuttle);
/**
* Accepts a visit from a shuttle. If the shuttle updates expression, then
* a copy of the relation should be created. This new relation might have
* a different row-type.
*
* @param shuttle Shuttle
* @return A copy of this node incorporating changes made by the shuttle to
* this node's children
*/
RelNode accept(RexShuttle shuttle);
/** Returns whether a field is nullable. */
default boolean fieldIsNullable(int i) {
return getRowType().getFieldList().get(i).getType().isNullable();
}
/** Context of a relational expression, for purposes of checking validity. */
interface Context {
Set<CorrelationId> correlationIds();
}
}