/* * 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 com.qihoo.qsql.org.apache.calcite.interpreter; import com.qihoo.qsql.org.apache.calcite.DataContext; import com.qihoo.qsql.org.apache.calcite.adapter.enumerable.AggImplementor; import com.qihoo.qsql.org.apache.calcite.adapter.enumerable.RexImpTable; import com.qihoo.qsql.org.apache.calcite.linq4j.Enumerable; import com.qihoo.qsql.org.apache.calcite.plan.Convention; import com.qihoo.qsql.org.apache.calcite.plan.RelOptCluster; import com.qihoo.qsql.org.apache.calcite.plan.RelOptCost; import com.qihoo.qsql.org.apache.calcite.plan.RelOptPlanner; import com.qihoo.qsql.org.apache.calcite.plan.RelOptRule; import com.qihoo.qsql.org.apache.calcite.plan.RelOptRuleCall; import com.qihoo.qsql.org.apache.calcite.plan.RelOptTable; import com.qihoo.qsql.org.apache.calcite.plan.RelOptUtil; import com.qihoo.qsql.org.apache.calcite.plan.RelTraitSet; import com.qihoo.qsql.org.apache.calcite.rel.InvalidRelException; import com.qihoo.qsql.org.apache.calcite.rel.RelCollation; import com.qihoo.qsql.org.apache.calcite.rel.RelCollationTraitDef; import com.qihoo.qsql.org.apache.calcite.rel.RelNode; import com.qihoo.qsql.org.apache.calcite.rel.RelWriter; import com.qihoo.qsql.org.apache.calcite.rel.convert.ConverterRule; import com.qihoo.qsql.org.apache.calcite.rel.core.Aggregate; import com.qihoo.qsql.org.apache.calcite.rel.core.AggregateCall; import com.qihoo.qsql.org.apache.calcite.rel.core.CorrelationId; import com.qihoo.qsql.org.apache.calcite.rel.core.Filter; import com.qihoo.qsql.org.apache.calcite.rel.core.Join; import com.qihoo.qsql.org.apache.calcite.rel.core.JoinRelType; import com.qihoo.qsql.org.apache.calcite.rel.core.Match; import com.qihoo.qsql.org.apache.calcite.rel.core.Project; import com.qihoo.qsql.org.apache.calcite.rel.core.RelFactories; import com.qihoo.qsql.org.apache.calcite.rel.core.Sort; import com.qihoo.qsql.org.apache.calcite.rel.core.TableScan; import com.qihoo.qsql.org.apache.calcite.rel.core.Union; import com.qihoo.qsql.org.apache.calcite.rel.core.Values; import com.qihoo.qsql.org.apache.calcite.rel.core.Window; import com.qihoo.qsql.org.apache.calcite.rel.logical.LogicalAggregate; import com.qihoo.qsql.org.apache.calcite.rel.logical.LogicalFilter; import com.qihoo.qsql.org.apache.calcite.rel.logical.LogicalJoin; import com.qihoo.qsql.org.apache.calcite.rel.logical.LogicalMatch; import com.qihoo.qsql.org.apache.calcite.rel.logical.LogicalProject; import com.qihoo.qsql.org.apache.calcite.rel.logical.LogicalTableScan; import com.qihoo.qsql.org.apache.calcite.rel.logical.LogicalUnion; import com.qihoo.qsql.org.apache.calcite.rel.logical.LogicalValues; import com.qihoo.qsql.org.apache.calcite.rel.logical.LogicalWindow; import com.qihoo.qsql.org.apache.calcite.rel.metadata.RelMdCollation; import com.qihoo.qsql.org.apache.calcite.rel.metadata.RelMetadataQuery; import com.qihoo.qsql.org.apache.calcite.rel.type.RelDataType; import com.qihoo.qsql.org.apache.calcite.rel.type.RelDataTypeFactory; import com.qihoo.qsql.org.apache.calcite.rel.type.RelDataTypeField; import com.qihoo.qsql.org.apache.calcite.rex.RexLiteral; import com.qihoo.qsql.org.apache.calcite.rex.RexNode; import com.qihoo.qsql.org.apache.calcite.schema.FilterableTable; import com.qihoo.qsql.org.apache.calcite.schema.ProjectableFilterableTable; import com.qihoo.qsql.org.apache.calcite.schema.ScannableTable; import com.qihoo.qsql.org.apache.calcite.schema.Table; import com.qihoo.qsql.org.apache.calcite.tools.RelBuilderFactory; import com.qihoo.qsql.org.apache.calcite.util.ImmutableBitSet; import com.qihoo.qsql.org.apache.calcite.util.ImmutableIntList; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.SortedSet; import java.util.function.Predicate; /** * Utilities pertaining to {@link BindableRel} and {@link BindableConvention}. */ public class Bindables { private Bindables() {} public static final RelOptRule BINDABLE_TABLE_SCAN_RULE = new BindableTableScanRule(RelFactories.LOGICAL_BUILDER); public static final RelOptRule BINDABLE_FILTER_RULE = new BindableFilterRule(RelFactories.LOGICAL_BUILDER); public static final RelOptRule BINDABLE_PROJECT_RULE = new BindableProjectRule(RelFactories.LOGICAL_BUILDER); public static final RelOptRule BINDABLE_SORT_RULE = new BindableSortRule(RelFactories.LOGICAL_BUILDER); public static final RelOptRule BINDABLE_JOIN_RULE = new BindableJoinRule(RelFactories.LOGICAL_BUILDER); public static final RelOptRule BINDABLE_UNION_RULE = new BindableUnionRule(RelFactories.LOGICAL_BUILDER); public static final RelOptRule BINDABLE_VALUES_RULE = new BindableValuesRule(RelFactories.LOGICAL_BUILDER); public static final RelOptRule BINDABLE_AGGREGATE_RULE = new BindableAggregateRule(RelFactories.LOGICAL_BUILDER); public static final RelOptRule BINDABLE_WINDOW_RULE = new BindableWindowRule(RelFactories.LOGICAL_BUILDER); public static final RelOptRule BINDABLE_MATCH_RULE = new BindableMatchRule(RelFactories.LOGICAL_BUILDER); /** All rules that convert logical relational expression to bindable. */ public static final ImmutableList<RelOptRule> RULES = ImmutableList.of( NoneToBindableConverterRule.INSTANCE, BINDABLE_TABLE_SCAN_RULE, BINDABLE_FILTER_RULE, BINDABLE_PROJECT_RULE, BINDABLE_SORT_RULE, BINDABLE_JOIN_RULE, BINDABLE_UNION_RULE, BINDABLE_VALUES_RULE, BINDABLE_AGGREGATE_RULE, BINDABLE_WINDOW_RULE, BINDABLE_MATCH_RULE); /** Helper method that converts a bindable relational expression into a * record iterator. * * <p>Any bindable can be compiled; if its input is also bindable, it becomes * part of the same compilation unit. */ private static Enumerable<Object[]> help(DataContext dataContext, BindableRel rel) { return new Interpreter(dataContext, rel); } /** Rule that converts a {@link com.qihoo.qsql.org.apache.calcite.rel.core.TableScan} * to bindable convention. */ public static class BindableTableScanRule extends RelOptRule { /** * Creates a BindableTableScanRule. * * @param relBuilderFactory Builder for relational expressions */ public BindableTableScanRule(RelBuilderFactory relBuilderFactory) { super(operand(LogicalTableScan.class, none()), relBuilderFactory, null); } @Override public void onMatch(RelOptRuleCall call) { final LogicalTableScan scan = call.rel(0); final RelOptTable table = scan.getTable(); if (BindableTableScan.canHandle(table)) { call.transformTo( BindableTableScan.create(scan.getCluster(), table)); } } } /** Scan of a table that implements {@link ScannableTable} and therefore can * be converted into an {@link Enumerable}. */ public static class BindableTableScan extends TableScan implements BindableRel { public final ImmutableList<RexNode> filters; public final ImmutableIntList projects; /** Creates a BindableTableScan. * * <p>Use {@link #create} unless you know what you are doing. */ BindableTableScan(RelOptCluster cluster, RelTraitSet traitSet, RelOptTable table, ImmutableList<RexNode> filters, ImmutableIntList projects) { super(cluster, traitSet, table); this.filters = Objects.requireNonNull(filters); this.projects = Objects.requireNonNull(projects); Preconditions.checkArgument(canHandle(table)); } /** Creates a BindableTableScan. */ public static BindableTableScan create(RelOptCluster cluster, RelOptTable relOptTable) { return create(cluster, relOptTable, ImmutableList.of(), identity(relOptTable)); } /** Creates a BindableTableScan. */ public static BindableTableScan create(RelOptCluster cluster, RelOptTable relOptTable, List<RexNode> filters, List<Integer> projects) { final Table table = relOptTable.unwrap(Table.class); final RelTraitSet traitSet = cluster.traitSetOf(BindableConvention.INSTANCE) .replaceIfs(RelCollationTraitDef.INSTANCE, () -> { if (table != null) { return table.getStatistic().getCollations(); } return ImmutableList.of(); }); return new BindableTableScan(cluster, traitSet, relOptTable, ImmutableList.copyOf(filters), ImmutableIntList.copyOf(projects)); } @Override public RelDataType deriveRowType() { final RelDataTypeFactory.Builder builder = getCluster().getTypeFactory().builder(); final List<RelDataTypeField> fieldList = table.getRowType().getFieldList(); for (int project : projects) { builder.add(fieldList.get(project)); } return builder.build(); } public Class<Object[]> getElementType() { return Object[].class; } @Override public RelWriter explainTerms(RelWriter pw) { return super.explainTerms(pw) .itemIf("filters", filters, !filters.isEmpty()) .itemIf("projects", projects, !projects.equals(identity())); } @Override public RelOptCost computeSelfCost(RelOptPlanner planner, RelMetadataQuery mq) { // Cost factor for pushing filters double f = filters.isEmpty() ? 1d : 0.5d; // Cost factor for pushing fields // The "+ 2d" on top and bottom keeps the function fairly smooth. double p = ((double) projects.size() + 2d) / ((double) table.getRowType().getFieldCount() + 2d); // Multiply the cost by a factor that makes a scan more attractive if // filters and projects are pushed to the table scan return super.computeSelfCost(planner, mq) .multiplyBy(f * p * 0.01d); } public static boolean canHandle(RelOptTable table) { return table.unwrap(ScannableTable.class) != null || table.unwrap(FilterableTable.class) != null || table.unwrap(ProjectableFilterableTable.class) != null; } public Enumerable<Object[]> bind(DataContext dataContext) { if (table.unwrap(ProjectableFilterableTable.class) != null) { return table.unwrap(ProjectableFilterableTable.class).scan(dataContext, filters, projects.toIntArray()); } else if (table.unwrap(FilterableTable.class) != null) { return table.unwrap(FilterableTable.class).scan(dataContext, filters); } else { return table.unwrap(ScannableTable.class).scan(dataContext); } } public Node implement(InterpreterImplementor implementor) { throw new UnsupportedOperationException(); // TODO: } } /** Rule that converts a {@link Filter} to bindable convention. */ public static class BindableFilterRule extends ConverterRule { /** * Creates a BindableFilterRule. * * @param relBuilderFactory Builder for relational expressions */ public BindableFilterRule(RelBuilderFactory relBuilderFactory) { super(LogicalFilter.class, (Predicate<LogicalFilter>) RelOptUtil::containsMultisetOrWindowedAgg, Convention.NONE, BindableConvention.INSTANCE, relBuilderFactory, "BindableFilterRule"); } public RelNode convert(RelNode rel) { final LogicalFilter filter = (LogicalFilter) rel; return BindableFilter.create( convert(filter.getInput(), filter.getInput().getTraitSet() .replace(BindableConvention.INSTANCE)), filter.getCondition()); } } /** Implementation of {@link com.qihoo.qsql.org.apache.calcite.rel.core.Filter} * in bindable convention. */ public static class BindableFilter extends Filter implements BindableRel { public BindableFilter(RelOptCluster cluster, RelTraitSet traitSet, RelNode input, RexNode condition) { super(cluster, traitSet, input, condition); assert getConvention() instanceof BindableConvention; } /** Creates a BindableFilter. */ public static BindableFilter create(final RelNode input, RexNode condition) { final RelOptCluster cluster = input.getCluster(); final RelMetadataQuery mq = cluster.getMetadataQuery(); final RelTraitSet traitSet = cluster.traitSetOf(BindableConvention.INSTANCE) .replaceIfs(RelCollationTraitDef.INSTANCE, () -> RelMdCollation.filter(mq, input)); return new BindableFilter(cluster, traitSet, input, condition); } public BindableFilter copy(RelTraitSet traitSet, RelNode input, RexNode condition) { return new BindableFilter(getCluster(), traitSet, input, condition); } public Class<Object[]> getElementType() { return Object[].class; } public Enumerable<Object[]> bind(DataContext dataContext) { return help(dataContext, this); } public Node implement(InterpreterImplementor implementor) { return new FilterNode(implementor.compiler, this); } } /** * Rule to convert a {@link com.qihoo.qsql.org.apache.calcite.rel.logical.LogicalProject} * to a {@link BindableProject}. */ public static class BindableProjectRule extends ConverterRule { /** * Creates a BindableProjectRule. * * @param relBuilderFactory Builder for relational expressions */ public BindableProjectRule(RelBuilderFactory relBuilderFactory) { super(LogicalProject.class, (Predicate<LogicalProject>) RelOptUtil::containsMultisetOrWindowedAgg, Convention.NONE, BindableConvention.INSTANCE, relBuilderFactory, "BindableProjectRule"); } public RelNode convert(RelNode rel) { final LogicalProject project = (LogicalProject) rel; return new BindableProject(rel.getCluster(), rel.getTraitSet().replace(BindableConvention.INSTANCE), convert(project.getInput(), project.getInput().getTraitSet() .replace(BindableConvention.INSTANCE)), project.getProjects(), project.getRowType()); } } /** Implementation of {@link com.qihoo.qsql.org.apache.calcite.rel.core.Project} in * bindable calling convention. */ public static class BindableProject extends Project implements BindableRel { public BindableProject(RelOptCluster cluster, RelTraitSet traitSet, RelNode input, List<? extends RexNode> projects, RelDataType rowType) { super(cluster, traitSet, input, projects, rowType); assert getConvention() instanceof BindableConvention; } public BindableProject copy(RelTraitSet traitSet, RelNode input, List<RexNode> projects, RelDataType rowType) { return new BindableProject(getCluster(), traitSet, input, projects, rowType); } public Class<Object[]> getElementType() { return Object[].class; } public Enumerable<Object[]> bind(DataContext dataContext) { return help(dataContext, this); } public Node implement(InterpreterImplementor implementor) { return new ProjectNode(implementor.compiler, this); } } /** * Rule to convert an {@link com.qihoo.qsql.org.apache.calcite.rel.core.Sort} to a * {@link com.qihoo.qsql.org.apache.calcite.interpreter.Bindables.BindableSort}. */ public static class BindableSortRule extends ConverterRule { /** * Creates a BindableSortRule. * * @param relBuilderFactory Builder for relational expressions */ public BindableSortRule(RelBuilderFactory relBuilderFactory) { super(Sort.class, (Predicate<RelNode>) r -> true, Convention.NONE, BindableConvention.INSTANCE, relBuilderFactory, "BindableSortRule"); } public RelNode convert(RelNode rel) { final Sort sort = (Sort) rel; final RelTraitSet traitSet = sort.getTraitSet().replace(BindableConvention.INSTANCE); final RelNode input = sort.getInput(); return new BindableSort(rel.getCluster(), traitSet, convert(input, input.getTraitSet().replace(BindableConvention.INSTANCE)), sort.getCollation(), sort.offset, sort.fetch); } } /** Implementation of {@link com.qihoo.qsql.org.apache.calcite.rel.core.Sort} * bindable calling convention. */ public static class BindableSort extends Sort implements BindableRel { public BindableSort(RelOptCluster cluster, RelTraitSet traitSet, RelNode input, RelCollation collation, RexNode offset, RexNode fetch) { super(cluster, traitSet, input, collation, offset, fetch); assert getConvention() instanceof BindableConvention; } @Override public BindableSort copy(RelTraitSet traitSet, RelNode newInput, RelCollation newCollation, RexNode offset, RexNode fetch) { return new BindableSort(getCluster(), traitSet, newInput, newCollation, offset, fetch); } public Class<Object[]> getElementType() { return Object[].class; } public Enumerable<Object[]> bind(DataContext dataContext) { return help(dataContext, this); } public Node implement(InterpreterImplementor implementor) { return new SortNode(implementor.compiler, this); } } /** * Rule to convert a {@link com.qihoo.qsql.org.apache.calcite.rel.logical.LogicalJoin} * to a {@link BindableJoin}. */ public static class BindableJoinRule extends ConverterRule { /** * Creates a BindableJoinRule. * * @param relBuilderFactory Builder for relational expressions */ public BindableJoinRule(RelBuilderFactory relBuilderFactory) { super(LogicalJoin.class, (Predicate<RelNode>) r -> true, Convention.NONE, BindableConvention.INSTANCE, relBuilderFactory, "BindableJoinRule"); } public RelNode convert(RelNode rel) { final LogicalJoin join = (LogicalJoin) rel; final BindableConvention out = BindableConvention.INSTANCE; final RelTraitSet traitSet = join.getTraitSet().replace(out); return new BindableJoin(rel.getCluster(), traitSet, convert(join.getLeft(), join.getLeft().getTraitSet() .replace(BindableConvention.INSTANCE)), convert(join.getRight(), join.getRight().getTraitSet() .replace(BindableConvention.INSTANCE)), join.getCondition(), join.getVariablesSet(), join.getJoinType()); } } /** Implementation of {@link com.qihoo.qsql.org.apache.calcite.rel.core.Join} in * bindable calling convention. */ public static class BindableJoin extends Join implements BindableRel { /** Creates a BindableJoin. */ protected BindableJoin(RelOptCluster cluster, RelTraitSet traitSet, RelNode left, RelNode right, RexNode condition, Set<CorrelationId> variablesSet, JoinRelType joinType) { super(cluster, traitSet, left, right, condition, variablesSet, joinType); } @Deprecated // to be removed before 2.0 protected BindableJoin(RelOptCluster cluster, RelTraitSet traitSet, RelNode left, RelNode right, RexNode condition, JoinRelType joinType, Set<String> variablesStopped) { this(cluster, traitSet, left, right, condition, CorrelationId.setOf(variablesStopped), joinType); } public BindableJoin copy(RelTraitSet traitSet, RexNode conditionExpr, RelNode left, RelNode right, JoinRelType joinType, boolean semiJoinDone) { return new BindableJoin(getCluster(), traitSet, left, right, conditionExpr, variablesSet, joinType); } public Class<Object[]> getElementType() { return Object[].class; } public Enumerable<Object[]> bind(DataContext dataContext) { return help(dataContext, this); } public Node implement(InterpreterImplementor implementor) { return new JoinNode(implementor.compiler, this); } } /** * Rule to convert an {@link com.qihoo.qsql.org.apache.calcite.rel.logical.LogicalUnion} * to a {@link BindableUnion}. */ public static class BindableUnionRule extends ConverterRule { /** * Creates a BindableUnionRule. * * @param relBuilderFactory Builder for relational expressions */ public BindableUnionRule(RelBuilderFactory relBuilderFactory) { super(LogicalUnion.class, (Predicate<RelNode>) r -> true, Convention.NONE, BindableConvention.INSTANCE, relBuilderFactory, "BindableUnionRule"); } public RelNode convert(RelNode rel) { final LogicalUnion union = (LogicalUnion) rel; final BindableConvention out = BindableConvention.INSTANCE; final RelTraitSet traitSet = union.getTraitSet().replace(out); return new BindableUnion(rel.getCluster(), traitSet, convertList(union.getInputs(), out), union.all); } } /** Implementation of {@link com.qihoo.qsql.org.apache.calcite.rel.core.Union} in * bindable calling convention. */ public static class BindableUnion extends Union implements BindableRel { public BindableUnion(RelOptCluster cluster, RelTraitSet traitSet, List<RelNode> inputs, boolean all) { super(cluster, traitSet, inputs, all); } public BindableUnion copy(RelTraitSet traitSet, List<RelNode> inputs, boolean all) { return new BindableUnion(getCluster(), traitSet, inputs, all); } public Class<Object[]> getElementType() { return Object[].class; } public Enumerable<Object[]> bind(DataContext dataContext) { return help(dataContext, this); } public Node implement(InterpreterImplementor implementor) { return new UnionNode(implementor.compiler, this); } } /** Implementation of {@link com.qihoo.qsql.org.apache.calcite.rel.core.Values} * in bindable calling convention. */ public static class BindableValues extends Values implements BindableRel { BindableValues(RelOptCluster cluster, RelDataType rowType, ImmutableList<ImmutableList<RexLiteral>> tuples, RelTraitSet traitSet) { super(cluster, rowType, tuples, traitSet); } @Override public RelNode copy(RelTraitSet traitSet, List<RelNode> inputs) { assert inputs.isEmpty(); return new BindableValues(getCluster(), rowType, tuples, traitSet); } public Class<Object[]> getElementType() { return Object[].class; } public Enumerable<Object[]> bind(DataContext dataContext) { return help(dataContext, this); } public Node implement(InterpreterImplementor implementor) { return new ValuesNode(implementor.compiler, this); } } /** Rule that converts a {@link Values} to bindable convention. */ public static class BindableValuesRule extends ConverterRule { /** * Creates a BindableValuesRule. * * @param relBuilderFactory Builder for relational expressions */ public BindableValuesRule(RelBuilderFactory relBuilderFactory) { super(LogicalValues.class, (Predicate<RelNode>) r -> true, Convention.NONE, BindableConvention.INSTANCE, relBuilderFactory, "BindableValuesRule"); } @Override public RelNode convert(RelNode rel) { LogicalValues values = (LogicalValues) rel; return new BindableValues(values.getCluster(), values.getRowType(), values.getTuples(), values.getTraitSet().replace(BindableConvention.INSTANCE)); } } /** Implementation of {@link com.qihoo.qsql.org.apache.calcite.rel.core.Aggregate} * in bindable calling convention. */ public static class BindableAggregate extends Aggregate implements BindableRel { public BindableAggregate( RelOptCluster cluster, RelTraitSet traitSet, RelNode input, ImmutableBitSet groupSet, List<ImmutableBitSet> groupSets, List<AggregateCall> aggCalls) throws InvalidRelException { super(cluster, traitSet, input, groupSet, groupSets, aggCalls); assert getConvention() instanceof BindableConvention; for (AggregateCall aggCall : aggCalls) { if (aggCall.isDistinct()) { throw new InvalidRelException( "distinct aggregation not supported"); } AggImplementor implementor2 = RexImpTable.INSTANCE.get(aggCall.getAggregation(), false); if (implementor2 == null) { throw new InvalidRelException( "aggregation " + aggCall.getAggregation() + " not supported"); } } } @Deprecated // to be removed before 2.0 public BindableAggregate(RelOptCluster cluster, RelTraitSet traitSet, RelNode input, boolean indicator, ImmutableBitSet groupSet, List<ImmutableBitSet> groupSets, List<AggregateCall> aggCalls) throws InvalidRelException { this(cluster, traitSet, input, groupSet, groupSets, aggCalls); checkIndicator(indicator); } @Override public BindableAggregate copy(RelTraitSet traitSet, RelNode input, ImmutableBitSet groupSet, List<ImmutableBitSet> groupSets, List<AggregateCall> aggCalls) { try { return new BindableAggregate(getCluster(), traitSet, input, groupSet, groupSets, aggCalls); } catch (InvalidRelException e) { // Semantic error not possible. Must be a bug. Convert to // internal error. throw new AssertionError(e); } } public Class<Object[]> getElementType() { return Object[].class; } public Enumerable<Object[]> bind(DataContext dataContext) { return help(dataContext, this); } public Node implement(InterpreterImplementor implementor) { return new AggregateNode(implementor.compiler, this); } } /** Rule that converts an {@link Aggregate} to bindable convention. */ public static class BindableAggregateRule extends ConverterRule { /** * Creates a BindableAggregateRule. * * @param relBuilderFactory Builder for relational expressions */ public BindableAggregateRule(RelBuilderFactory relBuilderFactory) { super(LogicalAggregate.class, (Predicate<RelNode>) r -> true, Convention.NONE, BindableConvention.INSTANCE, relBuilderFactory, "BindableAggregateRule"); } public RelNode convert(RelNode rel) { final LogicalAggregate agg = (LogicalAggregate) rel; final RelTraitSet traitSet = agg.getTraitSet().replace(BindableConvention.INSTANCE); try { return new BindableAggregate(rel.getCluster(), traitSet, convert(agg.getInput(), traitSet), false, agg.getGroupSet(), agg.getGroupSets(), agg.getAggCallList()); } catch (InvalidRelException e) { RelOptPlanner.LOGGER.debug(e.toString()); return null; } } } /** Implementation of {@link com.qihoo.qsql.org.apache.calcite.rel.core.Window} * in bindable convention. */ public static class BindableWindow extends Window implements BindableRel { /** Creates a BindableWindow. */ BindableWindow(RelOptCluster cluster, RelTraitSet traitSet, RelNode input, List<RexLiteral> constants, RelDataType rowType, List<Group> groups) { super(cluster, traitSet, input, constants, rowType, groups); } @Override public RelNode copy(RelTraitSet traitSet, List<RelNode> inputs) { return new BindableWindow(getCluster(), traitSet, sole(inputs), constants, rowType, groups); } @Override public RelOptCost computeSelfCost(RelOptPlanner planner, RelMetadataQuery mq) { return super.computeSelfCost(planner, mq) .multiplyBy(BindableConvention.COST_MULTIPLIER); } public Class<Object[]> getElementType() { return Object[].class; } public Enumerable<Object[]> bind(DataContext dataContext) { return help(dataContext, this); } public Node implement(InterpreterImplementor implementor) { return new WindowNode(implementor.compiler, this); } } /** * Rule to convert a {@link com.qihoo.qsql.org.apache.calcite.rel.logical.LogicalWindow} * to a {@link BindableWindow}. */ public static class BindableWindowRule extends ConverterRule { /** * Creates a BindableWindowRule. * * @param relBuilderFactory Builder for relational expressions */ public BindableWindowRule(RelBuilderFactory relBuilderFactory) { super(LogicalWindow.class, (Predicate<RelNode>) r -> true, Convention.NONE, BindableConvention.INSTANCE, relBuilderFactory, "BindableWindowRule"); } public RelNode convert(RelNode rel) { final LogicalWindow winAgg = (LogicalWindow) rel; final RelTraitSet traitSet = winAgg.getTraitSet().replace(BindableConvention.INSTANCE); final RelNode input = winAgg.getInput(); final RelNode convertedInput = convert(input, input.getTraitSet().replace(BindableConvention.INSTANCE)); return new BindableWindow(rel.getCluster(), traitSet, convertedInput, winAgg.getConstants(), winAgg.getRowType(), winAgg.groups); } } /** Implementation of {@link com.qihoo.qsql.org.apache.calcite.rel.core.Match} * in bindable convention. */ public static class BindableMatch extends Match implements BindableRel { /** Creates a BindableMatch. */ BindableMatch(RelOptCluster cluster, RelTraitSet traitSet, RelNode input, RelDataType rowType, RexNode pattern, boolean strictStart, boolean strictEnd, Map<String, RexNode> patternDefinitions, Map<String, RexNode> measures, RexNode after, Map<String, ? extends SortedSet<String>> subsets, boolean allRows, ImmutableBitSet partitionKeys, RelCollation orderKeys, RexNode interval) { super(cluster, traitSet, input, rowType, pattern, strictStart, strictEnd, patternDefinitions, measures, after, subsets, allRows, partitionKeys, orderKeys, interval); } @Override public RelNode copy(RelTraitSet traitSet, List<RelNode> inputs) { return new BindableMatch(getCluster(), traitSet, inputs.get(0), rowType, pattern, strictStart, strictEnd, patternDefinitions, measures, after, subsets, allRows, partitionKeys, orderKeys, interval); } public Class<Object[]> getElementType() { return Object[].class; } public Enumerable<Object[]> bind(DataContext dataContext) { return help(dataContext, this); } public Node implement(InterpreterImplementor implementor) { return new MatchNode(implementor.compiler, this); } } /** * Rule to convert a {@link com.qihoo.qsql.org.apache.calcite.rel.logical.LogicalMatch} * to a {@link BindableMatch}. */ public static class BindableMatchRule extends ConverterRule { /** * Creates a BindableMatchRule. * * @param relBuilderFactory Builder for relational expressions */ public BindableMatchRule(RelBuilderFactory relBuilderFactory) { super(LogicalMatch.class, (Predicate<RelNode>) r -> true, Convention.NONE, BindableConvention.INSTANCE, relBuilderFactory, "BindableMatchRule"); } public RelNode convert(RelNode rel) { final LogicalMatch match = (LogicalMatch) rel; final RelTraitSet traitSet = match.getTraitSet().replace(BindableConvention.INSTANCE); final RelNode input = match.getInput(); final RelNode convertedInput = convert(input, input.getTraitSet().replace(BindableConvention.INSTANCE)); return new BindableMatch(rel.getCluster(), traitSet, convertedInput, match.getRowType(), match.getPattern(), match.isStrictStart(), match.isStrictEnd(), match.getPatternDefinitions(), match.getMeasures(), match.getAfter(), match.getSubsets(), match.isAllRows(), match.getPartitionKeys(), match.getOrderKeys(), match.getInterval()); } } } // End Bindables.java