org.apache.calcite.util.mapping.MappingType Java Examples

The following examples show how to use org.apache.calcite.util.mapping.MappingType. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: RelOptUtil.java    From calcite with Apache License 2.0 6 votes vote down vote up
/**
 * Returns a permutation describing where the Project's fields come from
 * after the Project is pushed down.
 */
public static Mappings.TargetMapping permutationPushDownProject(
    List<RexNode> nodes,
    RelDataType inputRowType,
    int sourceOffset,
    int targetOffset) {
  final Mappings.TargetMapping mapping =
      Mappings.create(MappingType.PARTIAL_FUNCTION,
          inputRowType.getFieldCount() + sourceOffset,
          nodes.size() + targetOffset);
  for (Ord<RexNode> node : Ord.zip(nodes)) {
    if (node.e instanceof RexInputRef) {
      mapping.set(
          ((RexInputRef) node.e).getIndex() + sourceOffset,
          node.i + targetOffset);
    }
  }
  return mapping;
}
 
Example #2
Source File: Project.java    From Bats with Apache License 2.0 6 votes vote down vote up
/**
 * Returns a mapping of a set of project expressions.
 *
 * <p>The mapping is an inverse surjection.
 * Every target has a source field, but
 * a source field may appear as zero, one, or more target fields.
 * Thus you can safely call
 * {@link org.apache.calcite.util.mapping.Mappings.TargetMapping#getTarget(int)}.
 *
 * @param inputFieldCount Number of input fields
 * @param projects Project expressions
 * @return Mapping of a set of project expressions, or null if projection is
 * not a mapping
 */
public static Mappings.TargetMapping getMapping(int inputFieldCount,
    List<? extends RexNode> projects) {
  if (inputFieldCount < projects.size()) {
    return null; // surjection is not possible
  }
  Mappings.TargetMapping mapping =
      Mappings.create(MappingType.INVERSE_SURJECTION,
          inputFieldCount, projects.size());
  for (Ord<RexNode> exp : Ord.<RexNode>zip(projects)) {
    if (!(exp.e instanceof RexInputRef)) {
      return null;
    }
    mapping.set(((RexInputRef) exp.e).getIndex(), exp.i);
  }
  return mapping;
}
 
Example #3
Source File: RelOptUtil.java    From calcite with Apache License 2.0 6 votes vote down vote up
/**
 * Returns a permutation describing where output fields come from. In
 * the returned map, value of {@code map.getTargetOpt(i)} is {@code n} if
 * field {@code i} projects input field {@code n}, -1 if it is an
 * expression.
 */
public static Mappings.TargetMapping permutation(
    List<RexNode> nodes,
    RelDataType inputRowType) {
  final Mappings.TargetMapping mapping =
      Mappings.create(
          MappingType.PARTIAL_FUNCTION,
          nodes.size(),
          inputRowType.getFieldCount());
  for (Ord<RexNode> node : Ord.zip(nodes)) {
    if (node.e instanceof RexInputRef) {
      mapping.set(
          node.i,
          ((RexInputRef) node.e).getIndex());
    }
  }
  return mapping;
}
 
Example #4
Source File: RelOptUtil.java    From calcite with Apache License 2.0 6 votes vote down vote up
/**
 * Returns a permutation describing where output fields come from. In
 * the returned map, value of {@code map.getTargetOpt(i)} is {@code n} if
 * field {@code i} projects input field {@code n} or applies a cast on
 * {@code n}, -1 if it is another expression.
 */
public static Mappings.TargetMapping permutationIgnoreCast(
    List<RexNode> nodes,
    RelDataType inputRowType) {
  final Mappings.TargetMapping mapping =
      Mappings.create(
          MappingType.PARTIAL_FUNCTION,
          nodes.size(),
          inputRowType.getFieldCount());
  for (Ord<RexNode> node : Ord.zip(nodes)) {
    if (node.e instanceof RexInputRef) {
      mapping.set(
          node.i,
          ((RexInputRef) node.e).getIndex());
    } else if (node.e.isA(SqlKind.CAST)) {
      final RexNode operand = ((RexCall) node.e).getOperands().get(0);
      if (operand instanceof RexInputRef) {
        mapping.set(node.i, ((RexInputRef) operand).getIndex());
      }
    }
  }
  return mapping;
}
 
Example #5
Source File: RelFieldTrimmer.java    From calcite with Apache License 2.0 6 votes vote down vote up
/** Creates a project with a dummy column, to protect the parts of the system
 * that cannot handle a relational expression with no columns.
 *
 * @param fieldCount Number of fields in the original relational expression
 * @param input Trimmed input
 * @param originalRelNode Source RelNode for hint propagation (or null if no propagation needed)
 * @return Dummy project
 */
protected TrimResult dummyProject(int fieldCount, RelNode input, RelNode originalRelNode) {
  final RelOptCluster cluster = input.getCluster();
  final Mapping mapping =
      Mappings.create(MappingType.INVERSE_SURJECTION, fieldCount, 1);
  if (input.getRowType().getFieldCount() == 1) {
    // Input already has one field (and may in fact be a dummy project we
    // created for the child). We can't do better.
    return result(input, mapping);
  }
  final RexLiteral expr =
      cluster.getRexBuilder().makeExactLiteral(BigDecimal.ZERO);
  relBuilder.push(input);
  relBuilder.project(ImmutableList.of(expr), ImmutableList.of("DUMMY"));
  RelNode newProject = relBuilder.build();
  if (originalRelNode != null) {
    newProject = RelOptUtil.propagateRelHints(originalRelNode, newProject);
  }
  return result(newProject, mapping);
}
 
Example #6
Source File: RelOptUtil.java    From Bats with Apache License 2.0 6 votes vote down vote up
/**
 * Returns a permutation describing where output fields come from. In
 * the returned map, value of {@code map.getTargetOpt(i)} is {@code n} if
 * field {@code i} projects input field {@code n} or applies a cast on
 * {@code n}, -1 if it is another expression.
 */
public static Mappings.TargetMapping permutationIgnoreCast(List<RexNode> nodes, RelDataType inputRowType) {
    final Mappings.TargetMapping mapping = Mappings.create(MappingType.PARTIAL_FUNCTION, nodes.size(),
            inputRowType.getFieldCount());
    for (Ord<RexNode> node : Ord.zip(nodes)) {
        if (node.e instanceof RexInputRef) {
            mapping.set(node.i, ((RexInputRef) node.e).getIndex());
        } else if (node.e.isA(SqlKind.CAST)) {
            final RexNode operand = ((RexCall) node.e).getOperands().get(0);
            if (operand instanceof RexInputRef) {
                mapping.set(node.i, ((RexInputRef) operand).getIndex());
            }
        }
    }
    return mapping;
}
 
Example #7
Source File: Project.java    From calcite with Apache License 2.0 6 votes vote down vote up
/**
 * Returns a mapping of a set of project expressions.
 *
 * <p>The mapping is an inverse surjection.
 * Every target has a source field, but no
 * source has more than one target.
 * Thus you can safely call
 * {@link org.apache.calcite.util.mapping.Mappings.TargetMapping#getSourceOpt(int)}.
 *
 * @param inputFieldCount Number of input fields
 * @param projects Project expressions
 * @return Mapping of a set of project expressions, or null if projection is
 * not a mapping
 */
public static Mappings.TargetMapping getMapping(int inputFieldCount,
    List<? extends RexNode> projects) {
  if (inputFieldCount < projects.size()) {
    return null; // surjection is not possible
  }
  Mappings.TargetMapping mapping =
      Mappings.create(MappingType.INVERSE_SURJECTION,
          inputFieldCount, projects.size());
  for (Ord<RexNode> exp : Ord.<RexNode>zip(projects)) {
    if (!(exp.e instanceof RexInputRef)) {
      return null;
    }

    int source = ((RexInputRef) exp.e).getIndex();
    if (mapping.getTargetOpt(source) != -1) {
      return null;
    }
    mapping.set(source, exp.i);
  }
  return mapping;
}
 
Example #8
Source File: FilterNLJMergeRule.java    From dremio-oss with Apache License 2.0 6 votes vote down vote up
@Override
public void onMatch(RelOptRuleCall call) {
  FilterPrel filter = call.rel(0);
  NestedLoopJoinPrel join = call.rel(1);

  if ((join.getProjectedFields() == null) || join.getProjectedFields().cardinality() == join.getInputRowType().getFieldCount()) {
    call.transformTo(NestedLoopJoinPrel.create(join.getCluster(), join.getTraitSet(), join.getLeft(), join.getRight(), join.getJoinType(), RelOptUtil.andJoinFilters(join.getCluster().getRexBuilder(), join.getCondition(), filter.getCondition()), join.getProjectedFields()));
  } else {
    // Current filter condition is written based on projected fields on join. In order to push this filter down we need to rewrite filter condition
    final ImmutableBitSet topProjectedColumns = RelOptUtil.InputFinder.bits(filter.getCondition());
    final ImmutableBitSet bottomProjectedColumns = join.getProjectedFields();

    Mapping mapping = Mappings.create(MappingType.SURJECTION, join.getRowType().getFieldCount(), join.getInputRowType().getFieldCount());
    for (Ord<Integer> ord : Ord.zip(bottomProjectedColumns)) {
      if (topProjectedColumns.get(ord.i)) {
        mapping.set(ord.i, ord.e);
      }
    }

    RexShuttle shuttle = new RexPermuteInputsShuttle(mapping);
    RexNode updatedCondition = shuttle.apply(filter.getCondition());

    call.transformTo(NestedLoopJoinPrel.create(join.getCluster(), join.getTraitSet(), join.getLeft(), join.getRight(), join.getJoinType(), RelOptUtil.andJoinFilters(join.getCluster().getRexBuilder(), join.getCondition(), updatedCondition), join.getProjectedFields()));
  }
}
 
Example #9
Source File: ExtendedAggregateExtractProjectRule.java    From flink with Apache License 2.0 5 votes vote down vote up
/**
 * Extract projects from the Aggregate and return the index mapping between the new projects
 * and it's input.
 */
private Mapping extractProjectsAndMapping(
	Aggregate aggregate,
	RelNode input,
	RelBuilder relBuilder) {

	// Compute which input fields are used.
	final ImmutableBitSet.Builder inputFieldsUsed = getInputFieldUsed(aggregate, input);

	final List<RexNode> projects = new ArrayList<>();
	final Mapping mapping =
		Mappings.create(MappingType.INVERSE_SURJECTION,
			aggregate.getInput().getRowType().getFieldCount(),
			inputFieldsUsed.cardinality());
	int j = 0;
	for (int i : inputFieldsUsed.build()) {
		projects.add(relBuilder.field(i));
		mapping.set(i, j++);
	}

	if (input instanceof Project) {
		// this will not create trivial projects
		relBuilder.project(projects);
	} else {
		relBuilder.project(projects, Collections.emptyList(), true);
	}

	return mapping;
}
 
Example #10
Source File: RexProgram.java    From calcite with Apache License 2.0 5 votes vote down vote up
/**
 * Returns a partial mapping of a set of project expressions.
 *
 * <p>The mapping is an inverse function.
 * Every target has a source field, but
 * a source might have 0, 1 or more targets.
 * Project expressions that do not consist of
 * a mapping are ignored.
 *
 * @param inputFieldCount Number of input fields
 * @return Mapping of a set of project expressions, never null
 */
public Mappings.TargetMapping getPartialMapping(int inputFieldCount) {
  Mappings.TargetMapping mapping =
      Mappings.create(MappingType.INVERSE_FUNCTION,
          inputFieldCount, projects.size());
  for (Ord<RexLocalRef> exp : Ord.zip(projects)) {
    RexNode rexNode = expandLocalRef(exp.e);
    if (rexNode instanceof RexInputRef) {
      mapping.set(((RexInputRef) rexNode).getIndex(), exp.i);
    }
  }
  return mapping;
}
 
Example #11
Source File: RelFieldTrimmer.java    From calcite with Apache License 2.0 5 votes vote down vote up
protected Mapping createMapping(ImmutableBitSet fieldsUsed, int fieldCount) {
  final Mapping mapping =
      Mappings.create(
          MappingType.INVERSE_SURJECTION,
          fieldCount,
          fieldsUsed.cardinality());
  int i = 0;
  for (int field : fieldsUsed) {
    mapping.set(field, i++);
  }
  return mapping;
}
 
Example #12
Source File: RelMdPredicates.java    From calcite with Apache License 2.0 5 votes vote down vote up
private void initializeMapping() {
  nextMapping = Mappings.create(MappingType.PARTIAL_FUNCTION,
      nSysFields + nFieldsLeft + nFieldsRight,
      nSysFields + nFieldsLeft + nFieldsRight);
  for (int i = 0; i < columnSets.length; i++) {
    BitSet c = columnSets[i];
    int t = c.nextSetBit(iterationIdx[i]);
    if (t < 0) {
      nextMapping = null;
      return;
    }
    nextMapping.set(columns[i], t);
    iterationIdx[i] = t + 1;
  }
}
 
Example #13
Source File: RelMdPredicates.java    From calcite with Apache License 2.0 5 votes vote down vote up
/**
 * Infers predicates for an Aggregate.
 *
 * <p>Pulls up predicates that only contains references to columns in the
 * GroupSet. For e.g.
 *
 * <blockquote><pre>
 * inputPullUpExprs : { a &gt; 7, b + c &lt; 10, a + e = 9}
 * groupSet         : { a, b}
 * pulledUpExprs    : { a &gt; 7}
 * </pre></blockquote>
 */
public RelOptPredicateList getPredicates(Aggregate agg, RelMetadataQuery mq) {
  final RelNode input = agg.getInput();
  final RexBuilder rexBuilder = agg.getCluster().getRexBuilder();
  final RelOptPredicateList inputInfo = mq.getPulledUpPredicates(input);
  final List<RexNode> aggPullUpPredicates = new ArrayList<>();

  ImmutableBitSet groupKeys = agg.getGroupSet();
  if (groupKeys.isEmpty()) {
    // "GROUP BY ()" can convert an empty relation to a non-empty relation, so
    // it is not valid to pull up predicates. In particular, consider the
    // predicate "false": it is valid on all input rows (trivially - there are
    // no rows!) but not on the output (there is one row).
    return RelOptPredicateList.EMPTY;
  }
  Mapping m = Mappings.create(MappingType.PARTIAL_FUNCTION,
      input.getRowType().getFieldCount(), agg.getRowType().getFieldCount());

  int i = 0;
  for (int j : groupKeys) {
    m.set(j, i++);
  }

  for (RexNode r : inputInfo.pulledUpPredicates) {
    ImmutableBitSet rCols = RelOptUtil.InputFinder.bits(r);
    if (groupKeys.contains(rCols)) {
      r = r.accept(new RexPermuteInputsShuttle(m, input));
      aggPullUpPredicates.add(r);
    }
  }
  return RelOptPredicateList.of(rexBuilder, aggPullUpPredicates);
}
 
Example #14
Source File: MutableRels.java    From calcite with Apache License 2.0 5 votes vote down vote up
/** Equivalent to
 * {@link RelOptUtil#createProject(org.apache.calcite.rel.RelNode, java.util.List)}
 * for {@link MutableRel}. */
public static MutableRel createProject(final MutableRel child,
    final List<Integer> posList) {
  final RelDataType rowType = child.rowType;
  if (Mappings.isIdentity(posList, rowType.getFieldCount())) {
    return child;
  }
  final Mapping mapping =
      Mappings.create(
          MappingType.INVERSE_SURJECTION,
          rowType.getFieldCount(),
          posList.size());
  for (int i = 0; i < posList.size(); i++) {
    mapping.set(posList.get(i), i);
  }
  return MutableProject.of(
      RelOptUtil.permute(child.cluster.getTypeFactory(), rowType, mapping),
      child,
      new AbstractList<RexNode>() {
        public int size() {
          return posList.size();
        }

        public RexNode get(int index) {
          final int pos = posList.get(index);
          return RexInputRef.of(pos, rowType);
        }
      });
}
 
Example #15
Source File: DremioFieldTrimmer.java    From dremio-oss with Apache License 2.0 5 votes vote down vote up
/**
 * Variant of {@link #trimFields(RelNode, ImmutableBitSet, Set)} for {@link ScanCrel}.
 */
@SuppressWarnings("unused")
public TrimResult trimFields(
    ScanCrel crel,
    ImmutableBitSet fieldsUsed,
    Set<RelDataTypeField> extraFields) {

  if(fieldsUsed.cardinality() == crel.getRowType().getFieldCount()) {
    return result(crel, Mappings.createIdentity(crel.getRowType().getFieldCount()));
  }

  if(fieldsUsed.cardinality() == 0) {
    // do something similar to dummy project but avoid using a scan field. This ensures the scan
    // does a skipAll operation rather than projectin a useless column.
    final RelOptCluster cluster = crel.getCluster();
    final Mapping mapping = Mappings.create(MappingType.INVERSE_SURJECTION, crel.getRowType().getFieldCount(), 1);
    final RexLiteral expr = cluster.getRexBuilder().makeExactLiteral(BigDecimal.ZERO);
    builder.push(crel);
    builder.project(ImmutableList.<RexNode>of(expr), ImmutableList.of("DUMMY"));
    return result(builder.build(), mapping);
  }

  final List<SchemaPath> paths = new ArrayList<>();
  final Mapping m = Mappings.create(MappingType.PARTIAL_FUNCTION, crel.getRowType().getFieldCount(), fieldsUsed.cardinality());
  int index = 0;
  for(int i : fieldsUsed) {
    paths.add(SchemaPath.getSimplePath(crel.getRowType().getFieldList().get(i).getName()));
    m.set(i, index);
    index++;
  }

  ScanCrel newCrel = crel.cloneWithProject(paths);
  return result(newCrel, m);
}
 
Example #16
Source File: ExtendedAggregateExtractProjectRule.java    From flink with Apache License 2.0 5 votes vote down vote up
/**
 * Extract projects from the Aggregate and return the index mapping between the new projects
 * and it's input.
 */
private Mapping extractProjectsAndMapping(
	Aggregate aggregate,
	RelNode input,
	RelBuilder relBuilder) {

	// Compute which input fields are used.
	final ImmutableBitSet.Builder inputFieldsUsed = getInputFieldUsed(aggregate, input);

	final List<RexNode> projects = new ArrayList<>();
	final Mapping mapping =
		Mappings.create(MappingType.INVERSE_SURJECTION,
			aggregate.getInput().getRowType().getFieldCount(),
			inputFieldsUsed.cardinality());
	int j = 0;
	for (int i : inputFieldsUsed.build()) {
		projects.add(relBuilder.field(i));
		mapping.set(i, j++);
	}

	if (input instanceof Project) {
		// this will not create trivial projects
		relBuilder.project(projects);
	} else {
		relBuilder.project(projects, Collections.emptyList(), true);
	}

	return mapping;
}
 
Example #17
Source File: RelOptUtil.java    From Bats with Apache License 2.0 5 votes vote down vote up
/**
 * Returns a permutation describing where output fields come from. In
 * the returned map, value of {@code map.getTargetOpt(i)} is {@code n} if
 * field {@code i} projects input field {@code n}, -1 if it is an
 * expression.
 */
public static Mappings.TargetMapping permutation(List<RexNode> nodes, RelDataType inputRowType) {
    final Mappings.TargetMapping mapping = Mappings.create(MappingType.PARTIAL_FUNCTION, nodes.size(),
            inputRowType.getFieldCount());
    for (Ord<RexNode> node : Ord.zip(nodes)) {
        if (node.e instanceof RexInputRef) {
            mapping.set(node.i, ((RexInputRef) node.e).getIndex());
        }
    }
    return mapping;
}
 
Example #18
Source File: RelFieldTrimmer.java    From Bats with Apache License 2.0 5 votes vote down vote up
protected Mapping createMapping(ImmutableBitSet fieldsUsed, int fieldCount) {
    final Mapping mapping = Mappings.create(MappingType.INVERSE_SURJECTION, fieldCount, fieldsUsed.cardinality());
    int i = 0;
    for (int field : fieldsUsed) {
        mapping.set(field, i++);
    }
    return mapping;
}
 
Example #19
Source File: RelFieldTrimmer.java    From Bats with Apache License 2.0 5 votes vote down vote up
/** Creates a project with a dummy column, to protect the parts of the system
 * that cannot handle a relational expression with no columns.
 *
 * @param fieldCount Number of fields in the original relational expression
 * @param input Trimmed input
 * @return Dummy project, or null if no dummy is required
 */
protected TrimResult dummyProject(int fieldCount, RelNode input) {
    final RelOptCluster cluster = input.getCluster();
    final Mapping mapping = Mappings.create(MappingType.INVERSE_SURJECTION, fieldCount, 1);
    if (input.getRowType().getFieldCount() == 1) {
        // Input already has one field (and may in fact be a dummy project we
        // created for the child). We can't do better.
        return result(input, mapping);
    }
    final RexLiteral expr = cluster.getRexBuilder().makeExactLiteral(BigDecimal.ZERO);
    relBuilder.push(input);
    relBuilder.project(ImmutableList.<RexNode> of(expr), ImmutableList.of("DUMMY"));
    return result(relBuilder.build(), mapping);
}
 
Example #20
Source File: RelMdPredicates.java    From Bats with Apache License 2.0 5 votes vote down vote up
private void initializeMapping() {
  nextMapping = Mappings.create(MappingType.PARTIAL_FUNCTION,
      nSysFields + nFieldsLeft + nFieldsRight,
      nSysFields + nFieldsLeft + nFieldsRight);
  for (int i = 0; i < columnSets.length; i++) {
    BitSet c = columnSets[i];
    int t = c.nextSetBit(iterationIdx[i]);
    if (t < 0) {
      nextMapping = null;
      return;
    }
    nextMapping.set(columns[i], t);
    iterationIdx[i] = t + 1;
  }
}
 
Example #21
Source File: RelMdPredicates.java    From Bats with Apache License 2.0 5 votes vote down vote up
/**
 * Infers predicates for an Aggregate.
 *
 * <p>Pulls up predicates that only contains references to columns in the
 * GroupSet. For e.g.
 *
 * <blockquote><pre>
 * inputPullUpExprs : { a &gt; 7, b + c &lt; 10, a + e = 9}
 * groupSet         : { a, b}
 * pulledUpExprs    : { a &gt; 7}
 * </pre></blockquote>
 */
public RelOptPredicateList getPredicates(Aggregate agg, RelMetadataQuery mq) {
  final RelNode input = agg.getInput();
  final RexBuilder rexBuilder = agg.getCluster().getRexBuilder();
  final RelOptPredicateList inputInfo = mq.getPulledUpPredicates(input);
  final List<RexNode> aggPullUpPredicates = new ArrayList<>();

  ImmutableBitSet groupKeys = agg.getGroupSet();
  if (groupKeys.isEmpty()) {
    // "GROUP BY ()" can convert an empty relation to a non-empty relation, so
    // it is not valid to pull up predicates. In particular, consider the
    // predicate "false": it is valid on all input rows (trivially - there are
    // no rows!) but not on the output (there is one row).
    return RelOptPredicateList.EMPTY;
  }
  Mapping m = Mappings.create(MappingType.PARTIAL_FUNCTION,
      input.getRowType().getFieldCount(), agg.getRowType().getFieldCount());

  int i = 0;
  for (int j : groupKeys) {
    m.set(j, i++);
  }

  for (RexNode r : inputInfo.pulledUpPredicates) {
    ImmutableBitSet rCols = RelOptUtil.InputFinder.bits(r);
    if (groupKeys.contains(rCols)) {
      r = r.accept(new RexPermuteInputsShuttle(m, input));
      aggPullUpPredicates.add(r);
    }
  }
  return RelOptPredicateList.of(rexBuilder, aggPullUpPredicates);
}
 
Example #22
Source File: RelMdPredicates.java    From Bats with Apache License 2.0 4 votes vote down vote up
/**
 * Infers predicates for a project.
 *
 * <ol>
 * <li>create a mapping from input to projection. Map only positions that
 * directly reference an input column.
 * <li>Expressions that only contain above columns are retained in the
 * Project's pullExpressions list.
 * <li>For e.g. expression 'a + e = 9' below will not be pulled up because 'e'
 * is not in the projection list.
 *
 * <blockquote><pre>
 * inputPullUpExprs:      {a &gt; 7, b + c &lt; 10, a + e = 9}
 * projectionExprs:       {a, b, c, e / 2}
 * projectionPullupExprs: {a &gt; 7, b + c &lt; 10}
 * </pre></blockquote>
 *
 * </ol>
 */
public RelOptPredicateList getPredicates(Project project,
    RelMetadataQuery mq) {
  final RelNode input = project.getInput();
  final RexBuilder rexBuilder = project.getCluster().getRexBuilder();
  final RelOptPredicateList inputInfo = mq.getPulledUpPredicates(input);
  final List<RexNode> projectPullUpPredicates = new ArrayList<>();

  ImmutableBitSet.Builder columnsMappedBuilder = ImmutableBitSet.builder();
  Mapping m = Mappings.create(MappingType.PARTIAL_FUNCTION,
      input.getRowType().getFieldCount(),
      project.getRowType().getFieldCount());

  for (Ord<RexNode> expr : Ord.zip(project.getProjects())) {
    if (expr.e instanceof RexInputRef) {
      int sIdx = ((RexInputRef) expr.e).getIndex();
      m.set(sIdx, expr.i);
      columnsMappedBuilder.set(sIdx);
    // Project can also generate constants. We need to include them.
    } else if (RexLiteral.isNullLiteral(expr.e)) {
      projectPullUpPredicates.add(
          rexBuilder.makeCall(SqlStdOperatorTable.IS_NULL,
              rexBuilder.makeInputRef(project, expr.i)));
    } else if (RexUtil.isConstant(expr.e)) {
      final List<RexNode> args =
          ImmutableList.of(rexBuilder.makeInputRef(project, expr.i), expr.e);
      final SqlOperator op = args.get(0).getType().isNullable()
          || args.get(1).getType().isNullable()
          ? SqlStdOperatorTable.IS_NOT_DISTINCT_FROM
          : SqlStdOperatorTable.EQUALS;
      projectPullUpPredicates.add(rexBuilder.makeCall(op, args));
    }
  }

  // Go over childPullUpPredicates. If a predicate only contains columns in
  // 'columnsMapped' construct a new predicate based on mapping.
  final ImmutableBitSet columnsMapped = columnsMappedBuilder.build();
  for (RexNode r : inputInfo.pulledUpPredicates) {
    RexNode r2 = projectPredicate(rexBuilder, input, r, columnsMapped);
    if (!r2.isAlwaysTrue()) {
      r2 = r2.accept(new RexPermuteInputsShuttle(m, input));
      projectPullUpPredicates.add(r2);
    }
  }
  return RelOptPredicateList.of(rexBuilder, projectPullUpPredicates);
}
 
Example #23
Source File: RelMdPredicates.java    From calcite with Apache License 2.0 4 votes vote down vote up
/**
 * Infers predicates for a project.
 *
 * <ol>
 * <li>create a mapping from input to projection. Map only positions that
 * directly reference an input column.
 * <li>Expressions that only contain above columns are retained in the
 * Project's pullExpressions list.
 * <li>For e.g. expression 'a + e = 9' below will not be pulled up because 'e'
 * is not in the projection list.
 *
 * <blockquote><pre>
 * inputPullUpExprs:      {a &gt; 7, b + c &lt; 10, a + e = 9}
 * projectionExprs:       {a, b, c, e / 2}
 * projectionPullupExprs: {a &gt; 7, b + c &lt; 10}
 * </pre></blockquote>
 *
 * </ol>
 */
public RelOptPredicateList getPredicates(Project project,
    RelMetadataQuery mq) {
  final RelNode input = project.getInput();
  final RexBuilder rexBuilder = project.getCluster().getRexBuilder();
  final RelOptPredicateList inputInfo = mq.getPulledUpPredicates(input);
  final List<RexNode> projectPullUpPredicates = new ArrayList<>();

  ImmutableBitSet.Builder columnsMappedBuilder = ImmutableBitSet.builder();
  Mapping m = Mappings.create(MappingType.PARTIAL_FUNCTION,
      input.getRowType().getFieldCount(),
      project.getRowType().getFieldCount());

  for (Ord<RexNode> expr : Ord.zip(project.getProjects())) {
    if (expr.e instanceof RexInputRef) {
      int sIdx = ((RexInputRef) expr.e).getIndex();
      m.set(sIdx, expr.i);
      columnsMappedBuilder.set(sIdx);
    // Project can also generate constants. We need to include them.
    } else if (RexLiteral.isNullLiteral(expr.e)) {
      projectPullUpPredicates.add(
          rexBuilder.makeCall(SqlStdOperatorTable.IS_NULL,
              rexBuilder.makeInputRef(project, expr.i)));
    } else if (RexUtil.isConstant(expr.e)) {
      final List<RexNode> args =
          ImmutableList.of(rexBuilder.makeInputRef(project, expr.i), expr.e);
      final SqlOperator op = args.get(0).getType().isNullable()
          || args.get(1).getType().isNullable()
          ? SqlStdOperatorTable.IS_NOT_DISTINCT_FROM
          : SqlStdOperatorTable.EQUALS;
      projectPullUpPredicates.add(rexBuilder.makeCall(op, args));
    }
  }

  // Go over childPullUpPredicates. If a predicate only contains columns in
  // 'columnsMapped' construct a new predicate based on mapping.
  final ImmutableBitSet columnsMapped = columnsMappedBuilder.build();
  for (RexNode r : inputInfo.pulledUpPredicates) {
    RexNode r2 = projectPredicate(rexBuilder, input, r, columnsMapped);
    if (!r2.isAlwaysTrue()) {
      r2 = r2.accept(new RexPermuteInputsShuttle(m, input));
      projectPullUpPredicates.add(r2);
    }
  }
  return RelOptPredicateList.of(rexBuilder, projectPullUpPredicates);
}
 
Example #24
Source File: ProjectNLJMergeRule.java    From dremio-oss with Apache License 2.0 4 votes vote down vote up
@Override
public void onMatch(RelOptRuleCall call) {
  ProjectPrel project = call.rel(0);
  NestedLoopJoinPrel nlj = call.rel(1);

  ImmutableBitSet topProjectedColumns = InputFinder.bits(project.getProjects(), null);

  ImmutableBitSet bottomProjectedColumns = null;
  if (nlj.getProjectedFields() == null) {
    bottomProjectedColumns = ImmutableBitSet.range(nlj.getRowType().getFieldCount());
  } else {
    bottomProjectedColumns = nlj.getProjectedFields();
  }

  ImmutableBitSet.Builder builder = ImmutableBitSet.builder();
  int field = 0;
  Mapping mapping = Mappings.create(MappingType.SURJECTION, bottomProjectedColumns.cardinality(), topProjectedColumns.cardinality());
  for (Ord<Integer> ord : Ord.zip(bottomProjectedColumns)) {
    if (topProjectedColumns.get(ord.i)) {
      builder.set(ord.e);
      mapping.set(ord.i, field);
      field++;
    }
  }

  if (builder.cardinality() == 0) {
    //project at least one column
    builder.set(0);
  }

  ImmutableBitSet newJoinProjectedFields = builder.build();

  if (newJoinProjectedFields.equals(nlj.getProjectedFields())) {
    return;
  }

  RexShuttle shuttle = new RexPermuteInputsShuttle(mapping);
  List<RexNode> newProjects = shuttle.apply(project.getProjects());

  NestedLoopJoinPrel newJoin = (NestedLoopJoinPrel) nlj.copy(newJoinProjectedFields);
  ProjectPrel newProject = ProjectPrel.create(nlj.getCluster(), project.getTraitSet(), newJoin, newProjects, project.getRowType());
  call.transformTo(newProject);
}
 
Example #25
Source File: EnumerableTraitsUtils.java    From calcite with Apache License 2.0 4 votes vote down vote up
static Pair<RelTraitSet, List<RelTraitSet>> deriveTraitsForProject(
    RelTraitSet childTraits, int childId, List<RexNode> exps,
    RelDataType inputRowType, RelDataTypeFactory typeFactory, RelTraitSet currentTraits) {
  final RelCollation collation = childTraits.getCollation();
  if (collation == null || collation == RelCollations.EMPTY) {
    return null;
  }

  final int maxField = Math.max(exps.size(),
      inputRowType.getFieldCount());
  Mappings.TargetMapping mapping = Mappings
      .create(MappingType.FUNCTION, maxField, maxField);
  for (Ord<RexNode> node : Ord.zip(exps)) {
    if (node.e instanceof RexInputRef) {
      mapping.set(((RexInputRef) node.e).getIndex(), node.i);
    } else if (node.e.isA(SqlKind.CAST)) {
      final RexNode operand = ((RexCall) node.e).getOperands().get(0);
      if (operand instanceof RexInputRef) {
        mapping.set(((RexInputRef) operand).getIndex(), node.i);
      }
    }
  }

  List<RelFieldCollation> collationFieldsToDerive = new ArrayList<>();
  for (RelFieldCollation rc : collation.getFieldCollations()) {
    if (isCollationOnTrivialExpr(exps, typeFactory, mapping, rc, false)) {
      collationFieldsToDerive.add(rc);
    } else {
      break;
    }
  }

  if (collationFieldsToDerive.size() > 0) {
    final RelCollation newCollation = RelCollations
        .of(collationFieldsToDerive).apply(mapping);
    return Pair.of(currentTraits.replace(newCollation),
        ImmutableList.of(currentTraits.replace(collation)));
  } else {
    return null;
  }
}
 
Example #26
Source File: Permutation.java    From Bats with Apache License 2.0 4 votes vote down vote up
public MappingType getMappingType() {
  return MappingType.BIJECTION;
}
 
Example #27
Source File: Permutation.java    From calcite with Apache License 2.0 4 votes vote down vote up
public MappingType getMappingType() {
  return MappingType.BIJECTION;
}
 
Example #28
Source File: Project.java    From calcite with Apache License 2.0 3 votes vote down vote up
/**
 * Returns a partial mapping of a set of project expressions.
 *
 * <p>The mapping is an inverse function.
 * Every target has a source field, but
 * a source might have 0, 1 or more targets.
 * Project expressions that do not consist of
 * a mapping are ignored.
 *
 * @param inputFieldCount Number of input fields
 * @param projects Project expressions
 * @return Mapping of a set of project expressions, never null
 */
public static Mappings.TargetMapping getPartialMapping(int inputFieldCount,
    List<? extends RexNode> projects) {
  Mappings.TargetMapping mapping =
      Mappings.create(MappingType.INVERSE_FUNCTION,
          inputFieldCount, projects.size());
  for (Ord<RexNode> exp : Ord.<RexNode>zip(projects)) {
    if (exp.e instanceof RexInputRef) {
      mapping.set(((RexInputRef) exp.e).getIndex(), exp.i);
    }
  }
  return mapping;
}
 
Example #29
Source File: Project.java    From Bats with Apache License 2.0 3 votes vote down vote up
/**
 * Returns a partial mapping of a set of project expressions.
 *
 * <p>The mapping is an inverse function.
 * Every target has a source field, but
 * a source might have 0, 1 or more targets.
 * Project expressions that do not consist of
 * a mapping are ignored.
 *
 * @param inputFieldCount Number of input fields
 * @param projects Project expressions
 * @return Mapping of a set of project expressions, never null
 */
public static Mappings.TargetMapping getPartialMapping(int inputFieldCount,
    List<? extends RexNode> projects) {
  Mappings.TargetMapping mapping =
      Mappings.create(MappingType.INVERSE_FUNCTION,
          inputFieldCount, projects.size());
  for (Ord<RexNode> exp : Ord.<RexNode>zip(projects)) {
    if (exp.e instanceof RexInputRef) {
      mapping.set(((RexInputRef) exp.e).getIndex(), exp.i);
    }
  }
  return mapping;
}