Java Code Examples for org.apache.calcite.tools.RelBuilder#project()

The following examples show how to use org.apache.calcite.tools.RelBuilder#project() . 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: FlinkSemiAntiJoinProjectTransposeRule.java    From flink with Apache License 2.0 6 votes vote down vote up
public void onMatch(RelOptRuleCall call) {
	LogicalJoin join = call.rel(0);
	LogicalProject project = call.rel(1);

	// convert the semi/anti join condition to reflect the LHS with the project
	// pulled up
	RexNode newCondition = adjustCondition(project, join);
	Join newJoin = LogicalJoin.create(
			project.getInput(), join.getRight(), newCondition, join.getVariablesSet(), join.getJoinType());

	// Create the new projection. Note that the projection expressions
	// are the same as the original because they only reference the LHS
	// of the semi/anti join and the semi/anti join only projects out the LHS
	final RelBuilder relBuilder = call.builder();
	relBuilder.push(newJoin);
	relBuilder.project(project.getProjects(), project.getRowType().getFieldNames());

	call.transformTo(relBuilder.build());
}
 
Example 2
Source File: SubQueryRemoveRule.java    From calcite with Apache License 2.0 6 votes vote down vote up
/**
 * Rewrites an EXISTS RexSubQuery into a {@link Join}.
 *
 * @param e            EXISTS sub-query to rewrite
 * @param variablesSet A set of variables used by a relational
 *                     expression of the specified RexSubQuery
 * @param logic        Logic for evaluating
 * @param builder      Builder
 *
 * @return Expression that may be used to replace the RexSubQuery
 */
private RexNode rewriteExists(RexSubQuery e, Set<CorrelationId> variablesSet,
    RelOptUtil.Logic logic, RelBuilder builder) {
  builder.push(e.rel);

  builder.project(builder.alias(builder.literal(true), "i"));
  switch (logic) {
  case TRUE:
    // Handles queries with single EXISTS in filter condition:
    // select e.deptno from emp as e
    // where exists (select deptno from emp)
    builder.aggregate(builder.groupKey(0));
    builder.as("dt");
    builder.join(JoinRelType.INNER, builder.literal(true), variablesSet);
    return builder.literal(true);
  default:
    builder.distinct();
  }

  builder.as("dt");

  builder.join(JoinRelType.LEFT, builder.literal(true), variablesSet);

  return builder.isNotNull(Util.last(builder.fields()));
}
 
Example 3
Source File: AggregateRemoveRule.java    From Bats with Apache License 2.0 6 votes vote down vote up
public void onMatch(RelOptRuleCall call) {
  final Aggregate aggregate = call.rel(0);
  final RelNode input = call.rel(1);
  if (!aggregate.getAggCallList().isEmpty() || aggregate.indicator) {
    return;
  }
  final RelMetadataQuery mq = call.getMetadataQuery();
  if (!SqlFunctions.isTrue(mq.areColumnsUnique(input, aggregate.getGroupSet()))) {
    return;
  }
  // Distinct is "GROUP BY c1, c2" (where c1, c2 are a set of columns on
  // which the input is unique, i.e. contain a key) and has no aggregate
  // functions. It can be removed.
  final RelNode newInput = convert(input, aggregate.getTraitSet().simplify());

  // If aggregate was projecting a subset of columns, add a project for the
  // same effect.
  final RelBuilder relBuilder = call.builder();
  relBuilder.push(newInput);
  if (newInput.getRowType().getFieldCount()
      > aggregate.getRowType().getFieldCount()) {
    relBuilder.project(relBuilder.fields(aggregate.getGroupSet().asList()));
  }
  call.transformTo(relBuilder.build());
}
 
Example 4
Source File: SubQueryRemoveRule.java    From Bats with Apache License 2.0 6 votes vote down vote up
/**
 * Rewrites an EXISTS RexSubQuery into a {@link Join}.
 *
 * @param e            EXISTS sub-query to rewrite
 * @param variablesSet A set of variables used by a relational
 *                     expression of the specified RexSubQuery
 * @param logic        Logic for evaluating
 * @param builder      Builder
 *
 * @return Expression that may be used to replace the RexSubQuery
 */
private RexNode rewriteExists(RexSubQuery e, Set<CorrelationId> variablesSet, RelOptUtil.Logic logic,
        RelBuilder builder) {
    builder.push(e.getRel());

    builder.project(builder.alias(builder.literal(true), "i"));
    switch (logic) {
    case TRUE:
        // Handles queries with single EXISTS in filter condition:
        // select e.deptno from emp as e
        // where exists (select deptno from emp)
        builder.aggregate(builder.groupKey(0));
        builder.as("dt");
        builder.join(JoinRelType.INNER, builder.literal(true), variablesSet);
        return builder.literal(true);
    default:
        builder.distinct();
    }

    builder.as("dt");

    builder.join(JoinRelType.LEFT, builder.literal(true), variablesSet);

    return builder.isNotNull(Util.last(builder.fields()));
}
 
Example 5
Source File: FlinkAggregateRemoveRule.java    From flink with Apache License 2.0 6 votes vote down vote up
public void onMatch(RelOptRuleCall call) {
	final Aggregate aggregate = call.rel(0);
	final RelNode input = call.rel(1);

	// Distinct is "GROUP BY c1, c2" (where c1, c2 are a set of columns on
	// which the input is unique, i.e. contain a key) and has no aggregate
	// functions or the functions we enumerated. It can be removed.
	final RelNode newInput = convert(input, aggregate.getTraitSet().simplify());

	// If aggregate was projecting a subset of columns, add a project for the
	// same effect.
	final RelBuilder relBuilder = call.builder();
	relBuilder.push(newInput);
	List<Integer> projectIndices = new ArrayList<>(aggregate.getGroupSet().asList());
	for (AggregateCall aggCall : aggregate.getAggCallList()) {
		projectIndices.addAll(aggCall.getArgList());
	}
	relBuilder.project(relBuilder.fields(projectIndices));
	// Create a project if some of the columns have become
	// NOT NULL due to aggregate functions are removed
	relBuilder.convert(aggregate.getRowType(), true);
	call.transformTo(relBuilder.build());
}
 
Example 6
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 7
Source File: CalcSplitRule.java    From Bats with Apache License 2.0 5 votes vote down vote up
@Override public void onMatch(RelOptRuleCall call) {
  final Calc calc = call.rel(0);
  final Pair<ImmutableList<RexNode>, ImmutableList<RexNode>> projectFilter =
      calc.getProgram().split();
  final RelBuilder relBuilder = call.builder();
  relBuilder.push(calc.getInput());
  relBuilder.filter(projectFilter.right);
  relBuilder.project(projectFilter.left, calc.getRowType().getFieldNames());
  call.transformTo(relBuilder.build());
}
 
Example 8
Source File: CalcSplitRule.java    From calcite with Apache License 2.0 5 votes vote down vote up
@Override public void onMatch(RelOptRuleCall call) {
  final Calc calc = call.rel(0);
  final Pair<ImmutableList<RexNode>, ImmutableList<RexNode>> projectFilter =
      calc.getProgram().split();
  final RelBuilder relBuilder = call.builder();
  relBuilder.push(calc.getInput());
  relBuilder.filter(projectFilter.right);
  relBuilder.project(projectFilter.left, calc.getRowType().getFieldNames());
  call.transformTo(relBuilder.build());
}
 
Example 9
Source File: SemiJoinProjectTransposeRule.java    From Bats with Apache License 2.0 5 votes vote down vote up
public void onMatch(RelOptRuleCall call) {
  SemiJoin semiJoin = call.rel(0);
  LogicalProject project = call.rel(1);

  // Convert the LHS semi-join keys to reference the child projection
  // expression; all projection expressions must be RexInputRefs,
  // otherwise, we wouldn't have created this semi-join.
  final List<Integer> newLeftKeys = new ArrayList<>();
  final List<Integer> leftKeys = semiJoin.getLeftKeys();
  final List<RexNode> projExprs = project.getProjects();
  for (int leftKey : leftKeys) {
    RexInputRef inputRef = (RexInputRef) projExprs.get(leftKey);
    newLeftKeys.add(inputRef.getIndex());
  }

  // convert the semijoin condition to reflect the LHS with the project
  // pulled up
  RexNode newCondition = adjustCondition(project, semiJoin);

  SemiJoin newSemiJoin =
      SemiJoin.create(project.getInput(), semiJoin.getRight(), newCondition,
          ImmutableIntList.copyOf(newLeftKeys), semiJoin.getRightKeys());

  // Create the new projection.  Note that the projection expressions
  // are the same as the original because they only reference the LHS
  // of the semijoin and the semijoin only projects out the LHS
  final RelBuilder relBuilder = call.builder();
  relBuilder.push(newSemiJoin);
  relBuilder.project(projExprs, project.getRowType().getFieldNames());

  call.transformTo(relBuilder.build());
}
 
Example 10
Source File: IncrementalUpdateUtils.java    From dremio-oss with Apache License 2.0 4 votes vote down vote up
public RelNode updateScan(IncrementallyUpdateable scan) {
  RelNode newScan = scan;
  RelDataTypeField refreshField = scan.getRowType().getField(refreshColumn, false, false);

  if (refreshField == null) {
    // Check if the field exist as part of the schema
    newScan = scan.projectInvisibleColumn(refreshColumn);
    if (newScan == null) {
      throw UserException.dataReadError()
          .message("Table does not include column identified for incremental update of name '%s'.", refreshColumn)
          .build(logger);
    }
    refreshField = newScan.getRowType().getField(refreshColumn, false, false);
  }

  switch(refreshField.getType().getSqlTypeName()) {
    case INTEGER:
    case BIGINT:
    case FLOAT:
    case DOUBLE:
    case VARCHAR:
    case TIMESTAMP:
    case DATE:
    case DECIMAL:
      break;
    default:
      throw UserException.dataReadError()
          .message("Dremio only supports incremental column update on INTEGER, BIGINT, FLOAT, DOUBLE, VARCHAR, TIMESTAMP, DATE, and DECIMAL types. The identified column was of type %s.", refreshField.getType().getSqlTypeName())
          .build(logger);
  }

  // No need to add a project if field name is correct
  if (UPDATE_COLUMN.equals(refreshColumn)) {
    return newScan;
  }

  final RelBuilder relBuilder = newCalciteRelBuilderWithoutContext(newScan.getCluster());

  relBuilder.push(newScan);

  List<String> newFieldNames = ImmutableList.<String>builder().addAll(newScan.getRowType().getFieldNames()).add(UPDATE_COLUMN).build();

  Iterable<RexNode> projects = Stream.concat(
      scan.getRowType().getFieldNames().stream().map(relBuilder::field),
      Stream.of(refreshRex(relBuilder)))
      .collect(Collectors.toList());
  relBuilder.project(projects, newFieldNames);

  return relBuilder.build();
}
 
Example 11
Source File: AggregateRemoveRule.java    From calcite with Apache License 2.0 4 votes vote down vote up
public void onMatch(RelOptRuleCall call) {
  final Aggregate aggregate = call.rel(0);
  final RelNode input = aggregate.getInput();
  final RelMetadataQuery mq = call.getMetadataQuery();
  if (!SqlFunctions.isTrue(mq.areColumnsUnique(input, aggregate.getGroupSet()))) {
    return;
  }

  final RelBuilder relBuilder = call.builder();
  final RexBuilder rexBuilder = relBuilder.getRexBuilder();
  final List<RexNode> projects = new ArrayList<>();
  for (AggregateCall aggCall : aggregate.getAggCallList()) {
    final SqlAggFunction aggregation = aggCall.getAggregation();
    if (aggregation.getKind() == SqlKind.SUM0) {
      // Bail out for SUM0 to avoid potential infinite rule matching,
      // because it may be generated by transforming SUM aggregate
      // function to SUM0 and COUNT.
      return;
    }
    final SqlSplittableAggFunction splitter =
        Objects.requireNonNull(
            aggregation.unwrap(SqlSplittableAggFunction.class));
    final RexNode singleton = splitter.singleton(
        rexBuilder, input.getRowType(), aggCall);
    projects.add(singleton);
  }

  final RelNode newInput = convert(input, aggregate.getTraitSet().simplify());
  relBuilder.push(newInput);
  if (!projects.isEmpty()) {
    projects.addAll(0, relBuilder.fields(aggregate.getGroupSet()));
    relBuilder.project(projects);
  } else if (newInput.getRowType().getFieldCount()
      > aggregate.getRowType().getFieldCount()) {
    // If aggregate was projecting a subset of columns, and there were no
    // aggregate functions, add a project for the same effect.
    relBuilder.project(relBuilder.fields(aggregate.getGroupSet()));
  }
  call.getPlanner().prune(aggregate);
  call.transformTo(relBuilder.build());
}
 
Example 12
Source File: AggregateProjectMergeRule.java    From calcite with Apache License 2.0 4 votes vote down vote up
public static RelNode apply(RelOptRuleCall call, Aggregate aggregate,
    Project project) {
  // Find all fields which we need to be straightforward field projections.
  final Set<Integer> interestingFields = RelOptUtil.getAllFields(aggregate);

  // Build the map from old to new; abort if any entry is not a
  // straightforward field projection.
  final Map<Integer, Integer> map = new HashMap<>();
  for (int source : interestingFields) {
    final RexNode rex = project.getProjects().get(source);
    if (!(rex instanceof RexInputRef)) {
      return null;
    }
    map.put(source, ((RexInputRef) rex).getIndex());
  }

  final ImmutableBitSet newGroupSet = aggregate.getGroupSet().permute(map);
  ImmutableList<ImmutableBitSet> newGroupingSets = null;
  if (aggregate.getGroupType() != Group.SIMPLE) {
    newGroupingSets =
        ImmutableBitSet.ORDERING.immutableSortedCopy(
            ImmutableBitSet.permute(aggregate.getGroupSets(), map));
  }

  final ImmutableList.Builder<AggregateCall> aggCalls =
      ImmutableList.builder();
  final int sourceCount = aggregate.getInput().getRowType().getFieldCount();
  final int targetCount = project.getInput().getRowType().getFieldCount();
  final Mappings.TargetMapping targetMapping =
      Mappings.target(map, sourceCount, targetCount);
  for (AggregateCall aggregateCall : aggregate.getAggCallList()) {
    aggCalls.add(aggregateCall.transform(targetMapping));
  }

  final Aggregate newAggregate =
      aggregate.copy(aggregate.getTraitSet(), project.getInput(),
          newGroupSet, newGroupingSets, aggCalls.build());

  // Add a project if the group set is not in the same order or
  // contains duplicates.
  final RelBuilder relBuilder = call.builder();
  relBuilder.push(newAggregate);
  final List<Integer> newKeys =
      Lists.transform(aggregate.getGroupSet().asList(), map::get);
  if (!newKeys.equals(newGroupSet.asList())) {
    final List<Integer> posList = new ArrayList<>();
    for (int newKey : newKeys) {
      posList.add(newGroupSet.indexOf(newKey));
    }
    for (int i = newAggregate.getGroupCount();
         i < newAggregate.getRowType().getFieldCount(); i++) {
      posList.add(i);
    }
    relBuilder.project(relBuilder.fields(posList));
  }

  return relBuilder.build();
}
 
Example 13
Source File: FlinkAggregateExpandDistinctAggregatesRule.java    From flink with Apache License 2.0 4 votes vote down vote up
/**
 * Given an {@link org.apache.calcite.rel.core.Aggregate}
 * and the ordinals of the arguments to a
 * particular call to an aggregate function, creates a 'select distinct'
 * relational expression which projects the group columns and those
 * arguments but nothing else.
 *
 * <p>For example, given
 *
 * <blockquote>
 * <pre>select f0, count(distinct f1), count(distinct f2)
 * from t group by f0</pre>
 * </blockquote>
 *
 * <p>and the argument list
 *
 * <blockquote>{2}</blockquote>
 *
 * <p>returns
 *
 * <blockquote>
 * <pre>select distinct f0, f2 from t</pre>
 * </blockquote>
 *
 * <p>The <code>sourceOf</code> map is populated with the source of each
 * column; in this case sourceOf.get(0) = 0, and sourceOf.get(1) = 2.
 *
 * @param relBuilder Relational expression builder
 * @param aggregate Aggregate relational expression
 * @param argList   Ordinals of columns to make distinct
 * @param filterArg Ordinal of column to filter on, or -1
 * @param sourceOf  Out parameter, is populated with a map of where each
 *                  output field came from
 * @return Aggregate relational expression which projects the required
 * columns
 */
private RelBuilder createSelectDistinct(RelBuilder relBuilder,
		Aggregate aggregate, List<Integer> argList, int filterArg,
		Map<Integer, Integer> sourceOf) {
	relBuilder.push(aggregate.getInput());
	final List<Pair<RexNode, String>> projects = new ArrayList<>();
	final List<RelDataTypeField> childFields =
			relBuilder.peek().getRowType().getFieldList();
	for (int i : aggregate.getGroupSet()) {
		sourceOf.put(i, projects.size());
		projects.add(RexInputRef.of2(i, childFields));
	}
	if (filterArg >= 0) {
		sourceOf.put(filterArg, projects.size());
		projects.add(RexInputRef.of2(filterArg, childFields));
	}
	for (Integer arg : argList) {
		if (filterArg >= 0) {
			// Implement
			//   agg(DISTINCT arg) FILTER $f
			// by generating
			//   SELECT DISTINCT ... CASE WHEN $f THEN arg ELSE NULL END AS arg
			// and then applying
			//   agg(arg)
			// as usual.
			//
			// It works except for (rare) agg functions that need to see null
			// values.
			final RexBuilder rexBuilder = aggregate.getCluster().getRexBuilder();
			final RexInputRef filterRef = RexInputRef.of(filterArg, childFields);
			final Pair<RexNode, String> argRef = RexInputRef.of2(arg, childFields);
			RexNode condition =
					rexBuilder.makeCall(SqlStdOperatorTable.CASE, filterRef,
							argRef.left,
							rexBuilder.makeNullLiteral(argRef.left.getType()));
			sourceOf.put(arg, projects.size());
			projects.add(Pair.of(condition, "i$" + argRef.right));
			continue;
		}
		if (sourceOf.get(arg) != null) {
			continue;
		}
		sourceOf.put(arg, projects.size());
		projects.add(RexInputRef.of2(arg, childFields));
	}
	relBuilder.project(Pair.left(projects), Pair.right(projects));

	// Get the distinct values of the GROUP BY fields and the arguments
	// to the agg functions.
	relBuilder.push(
			aggregate.copy(aggregate.getTraitSet(), relBuilder.build(),
					ImmutableBitSet.range(projects.size()),
					null, com.google.common.collect.ImmutableList.<AggregateCall>of()));
	return relBuilder;
}
 
Example 14
Source File: DrillMergeProjectRule.java    From Bats with Apache License 2.0 4 votes vote down vote up
@Override
public void onMatch(RelOptRuleCall call) {
  final Project topProject = call.rel(0);
  final Project bottomProject = call.rel(1);
  final RelBuilder relBuilder = call.builder();

  // If one or both projects are permutations, short-circuit the complex logic
  // of building a RexProgram.
  final Permutation topPermutation = topProject.getPermutation();
  if (topPermutation != null) {
    if (topPermutation.isIdentity()) {
      // Let ProjectRemoveRule handle this.
      return;
    }
    final Permutation bottomPermutation = bottomProject.getPermutation();
    if (bottomPermutation != null) {
      if (bottomPermutation.isIdentity()) {
        // Let ProjectRemoveRule handle this.
        return;
      }
      final Permutation product = topPermutation.product(bottomPermutation);
      relBuilder.push(bottomProject.getInput());
      relBuilder.project(relBuilder.fields(product),
          topProject.getRowType().getFieldNames());
      call.transformTo(relBuilder.build());
      return;
    }
  }

  // If we're not in force mode and the two projects reference identical
  // inputs, then return and let ProjectRemoveRule replace the projects.
  if (!force) {
    if (RexUtil.isIdentity(topProject.getProjects(),
        topProject.getInput().getRowType())) {
      return;
    }
  }

  final List<RexNode> pushedProjects =
      RelOptUtil.pushPastProject(topProject.getProjects(), bottomProject);
  final List<RexNode> newProjects = simplifyCast(pushedProjects);
  final RelNode input = bottomProject.getInput();
  if (RexUtil.isIdentity(newProjects, input.getRowType())) {
    if (force
        || input.getRowType().getFieldNames()
        .equals(topProject.getRowType().getFieldNames())) {
      call.transformTo(input);
      return;
    }
  }

  // replace the two projects with a combined projection
  relBuilder.push(bottomProject.getInput());
  relBuilder.project(newProjects, topProject.getRowType().getFieldNames());
  call.transformTo(relBuilder.build());
}
 
Example 15
Source File: MergeProjectRule.java    From dremio-oss with Apache License 2.0 4 votes vote down vote up
@Override
public void onMatch(RelOptRuleCall call) {
  final Project topProject = call.rel(0);
  final Project bottomProject = call.rel(1);
  final RelBuilder relBuilder = call.builder();

  // merge projects assuming it doesn't alter the unique count of flattens.
  final FlattenCounter counter = new FlattenCounter();
  counter.add(topProject);
  counter.add(bottomProject);
  final int uniqueFlattens = counter.getCount();

  // If one or both projects are permutations, short-circuit the complex logic
  // of building a RexProgram.
  final Permutation topPermutation = topProject.getPermutation();
  if (topPermutation != null) {
    if (topPermutation.isIdentity()) {
      // Let ProjectRemoveRule handle this.
      return;
    }
    final Permutation bottomPermutation = bottomProject.getPermutation();
    if (bottomPermutation != null) {
      if (bottomPermutation.isIdentity()) {
        // Let ProjectRemoveRule handle this.
        return;
      }
      final Permutation product = topPermutation.product(bottomPermutation);
      relBuilder.push(bottomProject.getInput());
      List<RexNode> exprs = relBuilder.fields(product);
      relBuilder.project(exprs, topProject.getRowType().getFieldNames());

      if(FlattenVisitors.count(exprs) == uniqueFlattens){
        call.transformTo(relBuilder.build());
      }
      return;
    }
  }

  final List<RexNode> newProjects =
      RelOptUtil.pushPastProject(topProject.getProjects(), bottomProject);
  final RelNode input = bottomProject.getInput();
  if (RexUtil.isIdentity(newProjects, input.getRowType()) && uniqueFlattens == 0) {
    call.transformTo(input);
    return;
  }

  // replace the two projects with a combined projection
  relBuilder.push(bottomProject.getInput());
  relBuilder.project(newProjects, topProject.getRowType().getFieldNames());
  if(FlattenVisitors.count(newProjects) == uniqueFlattens){
    call.transformTo(relBuilder.build());
  }
}
 
Example 16
Source File: UnionPullUpConstantsRule.java    From Bats with Apache License 2.0 4 votes vote down vote up
@Override public void onMatch(RelOptRuleCall call) {
  final Union union = call.rel(0);

  final int count = union.getRowType().getFieldCount();
  if (count == 1) {
    // No room for optimization since we cannot create an empty Project
    // operator. If we created a Project with one column, this rule would
    // cycle.
    return;
  }

  final RexBuilder rexBuilder = union.getCluster().getRexBuilder();
  final RelMetadataQuery mq = call.getMetadataQuery();
  final RelOptPredicateList predicates = mq.getPulledUpPredicates(union);
  if (predicates == null) {
    return;
  }

  final Map<Integer, RexNode> constants = new HashMap<>();
  for (Map.Entry<RexNode, RexNode> e : predicates.constantMap.entrySet()) {
    if (e.getKey() instanceof RexInputRef) {
      constants.put(((RexInputRef) e.getKey()).getIndex(), e.getValue());
    }
  }

  // None of the expressions are constant. Nothing to do.
  if (constants.isEmpty()) {
    return;
  }

  // Create expressions for Project operators before and after the Union
  List<RelDataTypeField> fields = union.getRowType().getFieldList();
  List<RexNode> topChildExprs = new ArrayList<>();
  List<String> topChildExprsFields = new ArrayList<>();
  List<RexNode> refs = new ArrayList<>();
  ImmutableBitSet.Builder refsIndexBuilder = ImmutableBitSet.builder();
  for (RelDataTypeField field : fields) {
    final RexNode constant = constants.get(field.getIndex());
    if (constant != null) {
      topChildExprs.add(constant);
      topChildExprsFields.add(field.getName());
    } else {
      final RexNode expr = rexBuilder.makeInputRef(union, field.getIndex());
      topChildExprs.add(expr);
      topChildExprsFields.add(field.getName());
      refs.add(expr);
      refsIndexBuilder.set(field.getIndex());
    }
  }
  ImmutableBitSet refsIndex = refsIndexBuilder.build();

  // Update top Project positions
  final Mappings.TargetMapping mapping =
      RelOptUtil.permutation(refs, union.getInput(0).getRowType()).inverse();
  topChildExprs = ImmutableList.copyOf(RexUtil.apply(mapping, topChildExprs));

  // Create new Project-Union-Project sequences
  final RelBuilder relBuilder = call.builder();
  for (RelNode input : union.getInputs()) {
    List<Pair<RexNode, String>> newChildExprs = new ArrayList<>();
    for (int j : refsIndex) {
      newChildExprs.add(
          Pair.of(rexBuilder.makeInputRef(input, j),
              input.getRowType().getFieldList().get(j).getName()));
    }
    if (newChildExprs.isEmpty()) {
      // At least a single item in project is required.
      newChildExprs.add(
          Pair.of(topChildExprs.get(0), topChildExprsFields.get(0)));
    }
    // Add the input with project on top
    relBuilder.push(input);
    relBuilder.project(Pair.left(newChildExprs), Pair.right(newChildExprs));
  }
  relBuilder.union(union.all, union.getInputs().size());
  // Create top Project fixing nullability of fields
  relBuilder.project(topChildExprs, topChildExprsFields);
  relBuilder.convert(union.getRowType(), false);

  call.transformTo(relBuilder.build());
}
 
Example 17
Source File: PushFilterPastProjectRule.java    From dremio-oss with Apache License 2.0 4 votes vote down vote up
@Override
public void onMatch(RelOptRuleCall call) {
  Filter filterRel = call.rel(0);
  Project projRel = call.rel(1);

  // get a conjunctions of the filter condition. For each conjunction, if it refers to ITEM or FLATTEN expression
  // then we could not pushed down. Otherwise, it's qualified to be pushed down.
  final List<RexNode> predList = RelOptUtil.conjunctions(filterRel.getCondition());

  final List<RexNode> qualifiedPredList = Lists.newArrayList();
  final List<RexNode> unqualifiedPredList = Lists.newArrayList();


  for (final RexNode pred : predList) {
    if (qualifies(pred, projRel.getProjects())) {
      qualifiedPredList.add(pred);
    } else {
      unqualifiedPredList.add(pred);
    }
  }

  final RexNode qualifedPred = RexUtil.composeConjunction(filterRel.getCluster().getRexBuilder(), qualifiedPredList, true);

  if (qualifedPred == null) {
    return;
  }

  // convert the filter to one that references the child of the project
  RexNode newCondition =
      RelOptUtil.pushPastProject(qualifedPred, projRel);

  RelBuilder relBuilder = relBuilderFactory.create(filterRel.getCluster(), null);
  relBuilder.push(projRel.getInput());
  relBuilder.filter(newCondition);
  relBuilder.project(Pair.left(projRel.getNamedProjects()), Pair.right(projRel.getNamedProjects()));

  final RexNode unqualifiedPred = RexUtil.composeConjunction(filterRel.getCluster().getRexBuilder(), unqualifiedPredList, true);

  if (unqualifiedPred == null) {
    call.transformTo(relBuilder.build());
  } else {
    // if there are filters not qualified to be pushed down, then we have to put those filters on top of
    // the new Project operator.
    // Filter -- unqualified filters
    //   \
    //    Project
    //     \
    //      Filter  -- qualified filters
    relBuilder.filter(unqualifiedPred);
    call.transformTo(relBuilder.build());
  }
}
 
Example 18
Source File: RewriteNdvAsHll.java    From dremio-oss with Apache License 2.0 4 votes vote down vote up
@Override
public void onMatch(RelOptRuleCall call) {
  final LogicalAggregate agg = call.rel(0);
  final RelDataTypeFactory typeFactory = agg.getCluster().getTypeFactory();

  List<AggregateCall> calls = new ArrayList<>();
  Set<Integer> hllApplications = new HashSet<>();

  int i = agg.getGroupCount();
  for (AggregateCall c : agg.getAggCallList()) {

    final int location = i;
    i++;

    if(!"NDV".equals(c.getAggregation().getName())) {
      calls.add(c);
      continue;
    }

    hllApplications.add(location);
    calls.add(AggregateCall.create(HyperLogLog.HLL, false, c.getArgList(), -1, typeFactory.createSqlType(SqlTypeName.VARBINARY, HyperLogLog.HLL_VARBINARY_SIZE), c.getName()));
  }

  if(hllApplications.isEmpty()) {
    return;
  }

  final RelBuilder builder = relBuilderFactory.create(agg.getCluster(), null);
  builder.push(agg.getInput());
  builder.aggregate(builder.groupKey(agg.getGroupSet().toArray()), calls);

  // add the hll application project.
  final List<RexNode> nodes = new ArrayList<>();
  for(int field = 0; field < agg.getRowType().getFieldCount(); field++) {
    if(!hllApplications.contains(field)) {
      nodes.add(builder.field(field));
      continue;
    }

    nodes.add(builder.call(HyperLogLog.HLL_DECODE, builder.field(field)));
  }
  builder.project(nodes);
  call.transformTo(builder.build());
}
 
Example 19
Source File: ProjectMergeRule.java    From calcite with Apache License 2.0 4 votes vote down vote up
public void onMatch(RelOptRuleCall call) {
  final Project topProject = call.rel(0);
  final Project bottomProject = call.rel(1);
  final RelBuilder relBuilder = call.builder();

  // If one or both projects are permutations, short-circuit the complex logic
  // of building a RexProgram.
  final Permutation topPermutation = topProject.getPermutation();
  if (topPermutation != null) {
    if (topPermutation.isIdentity()) {
      // Let ProjectRemoveRule handle this.
      return;
    }
    final Permutation bottomPermutation = bottomProject.getPermutation();
    if (bottomPermutation != null) {
      if (bottomPermutation.isIdentity()) {
        // Let ProjectRemoveRule handle this.
        return;
      }
      final Permutation product = topPermutation.product(bottomPermutation);
      relBuilder.push(bottomProject.getInput());
      relBuilder.project(relBuilder.fields(product),
          topProject.getRowType().getFieldNames());
      call.transformTo(relBuilder.build());
      return;
    }
  }

  // If we're not in force mode and the two projects reference identical
  // inputs, then return and let ProjectRemoveRule replace the projects.
  if (!force) {
    if (RexUtil.isIdentity(topProject.getProjects(),
        topProject.getInput().getRowType())) {
      return;
    }
  }

  final List<RexNode> newProjects =
      RelOptUtil.pushPastProjectUnlessBloat(topProject.getProjects(),
          bottomProject, bloat);
  if (newProjects == null) {
    // Merged projects are significantly more complex. Do not merge.
    return;
  }
  final RelNode input = bottomProject.getInput();
  if (RexUtil.isIdentity(newProjects, input.getRowType())) {
    if (force
        || input.getRowType().getFieldNames()
            .equals(topProject.getRowType().getFieldNames())) {
      call.transformTo(input);
      return;
    }
  }

  // replace the two projects with a combined projection
  relBuilder.push(bottomProject.getInput());
  relBuilder.project(newProjects, topProject.getRowType().getFieldNames());
  call.transformTo(relBuilder.build());
}
 
Example 20
Source File: AggregateReduceFunctionsRule.java    From Bats with Apache License 2.0 2 votes vote down vote up
/**
 * Add a calc with the expressions to compute the original agg calls from the
 * decomposed ones.
 *
 * @param relBuilder Builder of relational expressions; at the top of its
 *                   stack is its input
 * @param rowType The output row type of the original aggregate.
 * @param exprs The expressions to compute the original agg calls.
 */
protected void newCalcRel(RelBuilder relBuilder,
    RelDataType rowType,
    List<RexNode> exprs) {
  relBuilder.project(exprs, rowType.getFieldNames());
}