All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.hazelcast.org.apache.calcite.rel.metadata.RelMdCollation Maven / Gradle / Ivy

There is a newer version: 5.4.0
Show newest version
/*
 * 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 com.hazelcast.com.liance with
 * the License.  You may obtain a copy of the License at
 *
 * http://www.apache.com.hazelcast.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.hazelcast.org.apache.calcite.rel.metadata;

import com.hazelcast.org.apache.calcite.adapter.enumerable.EnumerableCorrelate;
import com.hazelcast.org.apache.calcite.adapter.enumerable.EnumerableHashJoin;
import com.hazelcast.org.apache.calcite.adapter.enumerable.EnumerableMergeJoin;
import com.hazelcast.org.apache.calcite.adapter.enumerable.EnumerableNestedLoopJoin;
import com.hazelcast.org.apache.calcite.adapter.jdbc.JdbcToEnumerableConverter;
import com.hazelcast.org.apache.calcite.linq4j.Ord;
import com.hazelcast.org.apache.calcite.plan.RelOptTable;
import com.hazelcast.org.apache.calcite.plan.hep.HepRelVertex;
import com.hazelcast.org.apache.calcite.plan.volcano.RelSubset;
import com.hazelcast.org.apache.calcite.rel.RelCollation;
import com.hazelcast.org.apache.calcite.rel.RelCollationTraitDef;
import com.hazelcast.org.apache.calcite.rel.RelCollations;
import com.hazelcast.org.apache.calcite.rel.RelFieldCollation;
import com.hazelcast.org.apache.calcite.rel.RelNode;
import com.hazelcast.org.apache.calcite.rel.core.Calc;
import com.hazelcast.org.apache.calcite.rel.core.Filter;
import com.hazelcast.org.apache.calcite.rel.core.Join;
import com.hazelcast.org.apache.calcite.rel.core.JoinRelType;
import com.hazelcast.org.apache.calcite.rel.core.Match;
import com.hazelcast.org.apache.calcite.rel.core.Project;
import com.hazelcast.org.apache.calcite.rel.core.Sort;
import com.hazelcast.org.apache.calcite.rel.core.SortExchange;
import com.hazelcast.org.apache.calcite.rel.core.TableModify;
import com.hazelcast.org.apache.calcite.rel.core.TableScan;
import com.hazelcast.org.apache.calcite.rel.core.Values;
import com.hazelcast.org.apache.calcite.rel.core.Window;
import com.hazelcast.org.apache.calcite.rel.type.RelDataType;
import com.hazelcast.org.apache.calcite.rex.RexCall;
import com.hazelcast.org.apache.calcite.rex.RexCallBinding;
import com.hazelcast.org.apache.calcite.rex.RexInputRef;
import com.hazelcast.org.apache.calcite.rex.RexLiteral;
import com.hazelcast.org.apache.calcite.rex.RexNode;
import com.hazelcast.org.apache.calcite.rex.RexProgram;
import com.hazelcast.org.apache.calcite.sql.validate.SqlMonotonicity;
import com.hazelcast.org.apache.calcite.util.BuiltInMethod;
import com.hazelcast.org.apache.calcite.util.ImmutableBitSet;
import com.hazelcast.org.apache.calcite.util.ImmutableIntList;
import com.hazelcast.org.apache.calcite.util.Pair;
import com.hazelcast.org.apache.calcite.util.Util;

import com.hazelcast.com.google.com.hazelcast.com.on.collect.ImmutableList;
import com.hazelcast.com.google.com.hazelcast.com.on.collect.LinkedListMultimap;
import com.hazelcast.com.google.com.hazelcast.com.on.collect.Multimap;
import com.hazelcast.com.google.com.hazelcast.com.on.collect.Ordering;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.stream.Collectors;

/**
 * RelMdCollation supplies a default implementation of
 * {@link com.hazelcast.org.apache.calcite.rel.metadata.RelMetadataQuery#collations}
 * for the standard logical algebra.
 */
public class RelMdCollation
    implements MetadataHandler {
  public static final RelMetadataProvider SOURCE =
      ReflectiveRelMetadataProvider.reflectiveSource(
          BuiltInMethod.COLLATIONS.method, new RelMdCollation());

  //~ Constructors -----------------------------------------------------------

  private RelMdCollation() {}

  //~ Methods ----------------------------------------------------------------

  public MetadataDef getDef() {
    return BuiltInMetadata.Collation.DEF;
  }

  /** Catch-all implementation for
   * {@link BuiltInMetadata.Collation#collations()},
   * invoked using reflection, for any relational expression not
   * handled by a more specific method.
   *
   * 

{@link com.hazelcast.org.apache.calcite.rel.core.Union}, * {@link com.hazelcast.org.apache.calcite.rel.core.Intersect}, * {@link com.hazelcast.org.apache.calcite.rel.core.Minus}, * {@link com.hazelcast.org.apache.calcite.rel.core.Join}, * {@link com.hazelcast.org.apache.calcite.rel.core.Correlate} * do not in general return sorted results * (but implementations using particular algorithms may). * * @param rel Relational expression * @return Relational expression's collations * * @see com.hazelcast.org.apache.calcite.rel.metadata.RelMetadataQuery#collations(RelNode) */ public ImmutableList collations(RelNode rel, RelMetadataQuery mq) { return ImmutableList.of(); } public ImmutableList collations(Window rel, RelMetadataQuery mq) { return ImmutableList.copyOf(window(mq, rel.getInput(), rel.groups)); } public ImmutableList collations(Match rel, RelMetadataQuery mq) { return ImmutableList.copyOf( match(mq, rel.getInput(), rel.getRowType(), rel.getPattern(), rel.isStrictStart(), rel.isStrictEnd(), rel.getPatternDefinitions(), rel.getMeasures(), rel.getAfter(), rel.getSubsets(), rel.isAllRows(), rel.getPartitionKeys(), rel.getOrderKeys(), rel.getInterval())); } public ImmutableList collations(Filter rel, RelMetadataQuery mq) { return mq.collations(rel.getInput()); } public ImmutableList collations(TableModify rel, RelMetadataQuery mq) { return mq.collations(rel.getInput()); } public ImmutableList collations(TableScan scan, RelMetadataQuery mq) { return ImmutableList.copyOf(table(scan.getTable())); } public ImmutableList collations(EnumerableMergeJoin join, RelMetadataQuery mq) { // In general a join is not sorted. But a merge join preserves the sort // order of the left and right sides. return ImmutableList.copyOf( RelMdCollation.mergeJoin(mq, join.getLeft(), join.getRight(), join.analyzeCondition().leftKeys, join.analyzeCondition().rightKeys, join.getJoinType())); } public ImmutableList collations(EnumerableHashJoin join, RelMetadataQuery mq) { return ImmutableList.copyOf( RelMdCollation.enumerableHashJoin(mq, join.getLeft(), join.getRight(), join.getJoinType())); } public ImmutableList collations(EnumerableNestedLoopJoin join, RelMetadataQuery mq) { return ImmutableList.copyOf( RelMdCollation.enumerableNestedLoopJoin(mq, join.getLeft(), join.getRight(), join.getJoinType())); } public ImmutableList collations(EnumerableCorrelate join, RelMetadataQuery mq) { return ImmutableList.copyOf( RelMdCollation.enumerableCorrelate(mq, join.getLeft(), join.getRight(), join.getJoinType())); } public ImmutableList collations(Sort sort, RelMetadataQuery mq) { return ImmutableList.copyOf( RelMdCollation.sort(sort.getCollation())); } public ImmutableList collations(SortExchange sort, RelMetadataQuery mq) { return ImmutableList.copyOf( RelMdCollation.sort(sort.getCollation())); } public ImmutableList collations(Project project, RelMetadataQuery mq) { return ImmutableList.copyOf( project(mq, project.getInput(), project.getProjects())); } public ImmutableList collations(Calc calc, RelMetadataQuery mq) { return ImmutableList.copyOf(calc(mq, calc.getInput(), calc.getProgram())); } public ImmutableList collations(Values values, RelMetadataQuery mq) { return ImmutableList.copyOf( values(mq, values.getRowType(), values.getTuples())); } public ImmutableList collations(JdbcToEnumerableConverter rel, RelMetadataQuery mq) { return mq.collations(rel.getInput()); } public ImmutableList collations(HepRelVertex rel, RelMetadataQuery mq) { return mq.collations(rel.getCurrentRel()); } public ImmutableList collations(RelSubset rel, RelMetadataQuery mq) { return ImmutableList.copyOf( Objects.requireNonNull( rel.getTraitSet().getTraits(RelCollationTraitDef.INSTANCE))); } // Helper methods /** Helper method to determine a * {@link com.hazelcast.org.apache.calcite.rel.core.TableScan}'s collation. */ public static List table(RelOptTable table) { return table.getCollationList(); } /** Helper method to determine a * {@link com.hazelcast.org.apache.calcite.rel.core.Snapshot}'s collation. */ public static List snapshot(RelMetadataQuery mq, RelNode input) { return mq.collations(input); } /** Helper method to determine a * {@link com.hazelcast.org.apache.calcite.rel.core.Sort}'s collation. */ public static List sort(RelCollation collation) { return ImmutableList.of(collation); } /** Helper method to determine a * {@link com.hazelcast.org.apache.calcite.rel.core.Filter}'s collation. */ public static List filter(RelMetadataQuery mq, RelNode input) { return mq.collations(input); } /** Helper method to determine a * limit's collation. */ public static List limit(RelMetadataQuery mq, RelNode input) { return mq.collations(input); } /** Helper method to determine a * {@link com.hazelcast.org.apache.calcite.rel.core.Calc}'s collation. */ public static List calc(RelMetadataQuery mq, RelNode input, RexProgram program) { final List projects = program .getProjectList() .stream() .map(program::expandLocalRef) .collect(Collectors.toList()); return project(mq, input, projects); } /** Helper method to determine a {@link Project}'s collation. */ public static List project(RelMetadataQuery mq, RelNode input, List projects) { final SortedSet collations = new TreeSet<>(); final List inputCollations = mq.collations(input); if (inputCollations == null || inputCollations.isEmpty()) { return ImmutableList.of(); } final Multimap targets = LinkedListMultimap.create(); final Map targetsWithMonotonicity = new HashMap<>(); for (Ord project : Ord.zip(projects)) { if (project.e instanceof RexInputRef) { targets.put(((RexInputRef) project.e).getIndex(), project.i); } else if (project.e instanceof RexCall) { final RexCall call = (RexCall) project.e; final RexCallBinding binding = RexCallBinding.create(input.getCluster().getTypeFactory(), call, inputCollations); targetsWithMonotonicity.put(project.i, call.getOperator().getMonotonicity(binding)); } } final List fieldCollations = new ArrayList<>(); loop: for (RelCollation ic : inputCollations) { if (ic.getFieldCollations().isEmpty()) { continue; } fieldCollations.clear(); for (RelFieldCollation ifc : ic.getFieldCollations()) { final Collection integers = targets.get(ifc.getFieldIndex()); if (integers.isEmpty()) { continue loop; // cannot do this collation } fieldCollations.add(ifc.withFieldIndex(integers.iterator().next())); } assert !fieldCollations.isEmpty(); collations.add(RelCollations.of(fieldCollations)); } final List fieldCollationsForRexCalls = new ArrayList<>(); for (Map.Entry entry : targetsWithMonotonicity.entrySet()) { final SqlMonotonicity value = entry.getValue(); switch (value) { case NOT_MONOTONIC: case CONSTANT: break; default: fieldCollationsForRexCalls.add( new RelFieldCollation(entry.getKey(), RelFieldCollation.Direction.of(value))); break; } } if (!fieldCollationsForRexCalls.isEmpty()) { collations.add(RelCollations.of(fieldCollationsForRexCalls)); } return ImmutableList.copyOf(collations); } /** Helper method to determine a * {@link com.hazelcast.org.apache.calcite.rel.core.Window}'s collation. * *

A Window projects the fields of its input first, followed by the output * from each of its windows. Assuming (quite reasonably) that the * implementation does not re-order its input rows, then any collations of its * input are preserved. */ public static List window(RelMetadataQuery mq, RelNode input, ImmutableList groups) { return mq.collations(input); } /** Helper method to determine a * {@link com.hazelcast.org.apache.calcite.rel.core.Match}'s collation. */ public static List match(RelMetadataQuery mq, RelNode input, RelDataType rowType, RexNode pattern, boolean strictStart, boolean strictEnd, Map patternDefinitions, Map measures, RexNode after, Map> subsets, boolean allRows, ImmutableBitSet partitionKeys, RelCollation orderKeys, RexNode interval) { return mq.collations(input); } /** Helper method to determine a * {@link com.hazelcast.org.apache.calcite.rel.core.Values}'s collation. * *

We actually under-report the collations. A Values with 0 or 1 rows - an * edge case, but legitimate and very com.hazelcast.com.on - is ordered by every permutation * of every subset of the columns. * *

So, our algorithm aims to:

    *
  • produce at most N collations (where N is the number of columns); *
  • make each collation as long as possible; *
  • do not repeat com.hazelcast.com.inations already emitted - * if we've emitted {@code (a, b)} do not later emit {@code (b, a)}; *
  • probe the actual values and make sure that each collation is * consistent with the data *
* *

So, for an empty Values with 4 columns, we would emit * {@code (a, b, c, d), (b, c, d), (c, d), (d)}. */ public static List values(RelMetadataQuery mq, RelDataType rowType, ImmutableList> tuples) { Util.discard(mq); // for future use final List list = new ArrayList<>(); final int n = rowType.getFieldCount(); final List>>> pairs = new ArrayList<>(); outer: for (int i = 0; i < n; i++) { pairs.clear(); for (int j = i; j < n; j++) { final RelFieldCollation fieldCollation = new RelFieldCollation(j); Ordering> com.hazelcast.com.arator = com.hazelcast.com.arator(fieldCollation); Ordering> ordering; if (pairs.isEmpty()) { ordering = com.hazelcast.com.arator; } else { ordering = Util.last(pairs).right.com.hazelcast.com.ound(com.hazelcast.com.arator); } pairs.add(Pair.of(fieldCollation, ordering)); if (!ordering.isOrdered(tuples)) { if (j == i) { continue outer; } pairs.remove(pairs.size() - 1); } } if (!pairs.isEmpty()) { list.add(RelCollations.of(Pair.left(pairs))); } } return list; } private static Ordering> com.hazelcast.com.arator( RelFieldCollation fieldCollation) { final int nullComparison = fieldCollation.nullDirection.nullComparison; final int x = fieldCollation.getFieldIndex(); switch (fieldCollation.direction) { case ASCENDING: return new Ordering>() { public int com.hazelcast.com.are(List o1, List o2) { final Comparable c1 = o1.get(x).getValueAs(Comparable.class); final Comparable c2 = o2.get(x).getValueAs(Comparable.class); return RelFieldCollation.com.hazelcast.com.are(c1, c2, nullComparison); } }; default: return new Ordering>() { public int com.hazelcast.com.are(List o1, List o2) { final Comparable c1 = o1.get(x).getValueAs(Comparable.class); final Comparable c2 = o2.get(x).getValueAs(Comparable.class); return RelFieldCollation.com.hazelcast.com.are(c2, c1, -nullComparison); } }; } } /** Helper method to determine a {@link Join}'s collation assuming that it * uses a merge-join algorithm. * *

If the inputs are sorted on other keys in addition to the join * key, the result preserves those collations too. * @deprecated Use {@link #mergeJoin(RelMetadataQuery, RelNode, RelNode, ImmutableIntList, ImmutableIntList, JoinRelType)} */ @Deprecated // to be removed before 2.0 public static List mergeJoin(RelMetadataQuery mq, RelNode left, RelNode right, ImmutableIntList leftKeys, ImmutableIntList rightKeys) { return mergeJoin(mq, left, right, leftKeys, rightKeys, JoinRelType.INNER); } /** Helper method to determine a {@link Join}'s collation assuming that it * uses a merge-join algorithm. * *

If the inputs are sorted on other keys in addition to the join * key, the result preserves those collations too. */ public static List mergeJoin(RelMetadataQuery mq, RelNode left, RelNode right, ImmutableIntList leftKeys, ImmutableIntList rightKeys, JoinRelType joinType) { assert EnumerableMergeJoin.isMergeJoinSupported(joinType) : "EnumerableMergeJoin unsupported for join type " + joinType; final ImmutableList leftCollations = mq.collations(left); assert RelCollations.contains(leftCollations, leftKeys) : "cannot merge join: left input is not sorted on left keys"; if (!joinType.projectsRight()) { return leftCollations; } final ImmutableList.Builder builder = ImmutableList.builder(); builder.addAll(leftCollations); final ImmutableList rightCollations = mq.collations(right); assert RelCollations.contains(rightCollations, rightKeys) : "cannot merge join: right input is not sorted on right keys"; final int leftFieldCount = left.getRowType().getFieldCount(); for (RelCollation collation : rightCollations) { builder.add(RelCollations.shift(collation, leftFieldCount)); } return builder.build(); } /** * Returns the collation of {@link EnumerableHashJoin} based on its inputs and the join type. */ public static List enumerableHashJoin(RelMetadataQuery mq, RelNode left, RelNode right, JoinRelType joinType) { if (joinType == JoinRelType.SEMI) { return enumerableSemiJoin(mq, left, right); } else { return enumerableJoin0(mq, left, right, joinType); } } /** * Returns the collation of {@link EnumerableNestedLoopJoin} * based on its inputs and the join type. */ public static List enumerableNestedLoopJoin(RelMetadataQuery mq, RelNode left, RelNode right, JoinRelType joinType) { return enumerableJoin0(mq, left, right, joinType); } public static List enumerableCorrelate(RelMetadataQuery mq, RelNode left, RelNode right, JoinRelType joinType) { // The current implementation always preserve the sort order of the left input return mq.collations(left); } public static List enumerableSemiJoin(RelMetadataQuery mq, RelNode left, RelNode right) { // The current implementation always preserve the sort order of the left input return mq.collations(left); } public static List enumerableBatchNestedLoopJoin(RelMetadataQuery mq, RelNode left, RelNode right, JoinRelType joinType) { // The current implementation always preserve the sort order of the left input return mq.collations(left); } private static List enumerableJoin0(RelMetadataQuery mq, RelNode left, RelNode right, JoinRelType joinType) { // The current implementation can preserve the sort order of the left input if one of the // following conditions hold: // (i) join type is INNER or LEFT; // (ii) RelCollation always orders nulls last. final ImmutableList leftCollations = mq.collations(left); switch (joinType) { case SEMI: case ANTI: case INNER: case LEFT: return leftCollations; case RIGHT: case FULL: for (RelCollation collation : leftCollations) { for (RelFieldCollation field : collation.getFieldCollations()) { if (!(RelFieldCollation.NullDirection.LAST == field.nullDirection)) { return ImmutableList.of(); } } } return leftCollations; } return ImmutableList.of(); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy