use of org.apache.beam.vendor.calcite.v1_28_0.org.apache.calcite.rel.type.RelDataTypeField in project calcite by apache.
the class RelDecorrelator method projectJoinOutputWithNullability.
/**
* Pulls project above the join from its RHS input. Enforces nullability
* for join output.
*
* @param join Join
* @param project Original project as the right-hand input of the join
* @param nullIndicatorPos Position of null indicator
* @return the subtree with the new Project at the root
*/
private RelNode projectJoinOutputWithNullability(LogicalJoin join, LogicalProject project, int nullIndicatorPos) {
final RelDataTypeFactory typeFactory = join.getCluster().getTypeFactory();
final RelNode left = join.getLeft();
final JoinRelType joinType = join.getJoinType();
RexInputRef nullIndicator = new RexInputRef(nullIndicatorPos, typeFactory.createTypeWithNullability(join.getRowType().getFieldList().get(nullIndicatorPos).getType(), true));
// now create the new project
List<Pair<RexNode, String>> newProjExprs = Lists.newArrayList();
// project everything from the LHS and then those from the original
// projRel
List<RelDataTypeField> leftInputFields = left.getRowType().getFieldList();
for (int i = 0; i < leftInputFields.size(); i++) {
newProjExprs.add(RexInputRef.of2(i, leftInputFields));
}
// Marked where the projected expr is coming from so that the types will
// become nullable for the original projections which are now coming out
// of the nullable side of the OJ.
boolean projectPulledAboveLeftCorrelator = joinType.generatesNullsOnRight();
for (Pair<RexNode, String> pair : project.getNamedProjects()) {
RexNode newProjExpr = removeCorrelationExpr(pair.left, projectPulledAboveLeftCorrelator, nullIndicator);
newProjExprs.add(Pair.of(newProjExpr, pair.right));
}
return relBuilder.push(join).projectNamed(Pair.left(newProjExprs), Pair.right(newProjExprs), true).build();
}
use of org.apache.beam.vendor.calcite.v1_28_0.org.apache.calcite.rel.type.RelDataTypeField in project calcite by apache.
the class RelDecorrelator method decorrelateRel.
/**
* Rewrite Correlate into a left outer join.
*
* @param rel Correlator
*/
public Frame decorrelateRel(LogicalCorrelate rel) {
//
// Rewrite logic:
//
// The original left input will be joined with the new right input that
// has generated correlated variables propagated up. For any generated
// corVars that are not used in the join key, pass them along to be
// joined later with the Correlates that produce them.
//
// the right input to Correlate should produce correlated variables
final RelNode oldLeft = rel.getInput(0);
final RelNode oldRight = rel.getInput(1);
final Frame leftFrame = getInvoke(oldLeft, rel);
final Frame rightFrame = getInvoke(oldRight, rel);
if (leftFrame == null || rightFrame == null) {
// If any input has not been rewritten, do not rewrite this rel.
return null;
}
if (rightFrame.corDefOutputs.isEmpty()) {
return null;
}
assert rel.getRequiredColumns().cardinality() <= rightFrame.corDefOutputs.keySet().size();
// Change correlator rel into a join.
// Join all the correlated variables produced by this correlator rel
// with the values generated and propagated from the right input
final SortedMap<CorDef, Integer> corDefOutputs = new TreeMap<>(rightFrame.corDefOutputs);
final List<RexNode> conditions = new ArrayList<>();
final List<RelDataTypeField> newLeftOutput = leftFrame.r.getRowType().getFieldList();
int newLeftFieldCount = newLeftOutput.size();
final List<RelDataTypeField> newRightOutput = rightFrame.r.getRowType().getFieldList();
for (Map.Entry<CorDef, Integer> rightOutput : new ArrayList<>(corDefOutputs.entrySet())) {
final CorDef corDef = rightOutput.getKey();
if (!corDef.corr.equals(rel.getCorrelationId())) {
continue;
}
final int newLeftPos = leftFrame.oldToNewOutputs.get(corDef.field);
final int newRightPos = rightOutput.getValue();
conditions.add(relBuilder.call(SqlStdOperatorTable.EQUALS, RexInputRef.of(newLeftPos, newLeftOutput), new RexInputRef(newLeftFieldCount + newRightPos, newRightOutput.get(newRightPos).getType())));
// remove this corVar from output position mapping
corDefOutputs.remove(corDef);
}
// vars that are not used in the join key.
for (CorDef corDef : corDefOutputs.keySet()) {
int newPos = corDefOutputs.get(corDef) + newLeftFieldCount;
corDefOutputs.put(corDef, newPos);
}
// then add any corVar from the left input. Do not need to change
// output positions.
corDefOutputs.putAll(leftFrame.corDefOutputs);
// Create the mapping between the output of the old correlation rel
// and the new join rel
final Map<Integer, Integer> mapOldToNewOutputs = new HashMap<>();
int oldLeftFieldCount = oldLeft.getRowType().getFieldCount();
int oldRightFieldCount = oldRight.getRowType().getFieldCount();
assert rel.getRowType().getFieldCount() == oldLeftFieldCount + oldRightFieldCount;
// Left input positions are not changed.
mapOldToNewOutputs.putAll(leftFrame.oldToNewOutputs);
// Right input positions are shifted by newLeftFieldCount.
for (int i = 0; i < oldRightFieldCount; i++) {
mapOldToNewOutputs.put(i + oldLeftFieldCount, rightFrame.oldToNewOutputs.get(i) + newLeftFieldCount);
}
final RexNode condition = RexUtil.composeConjunction(relBuilder.getRexBuilder(), conditions, false);
RelNode newJoin = LogicalJoin.create(leftFrame.r, rightFrame.r, condition, ImmutableSet.<CorrelationId>of(), rel.getJoinType().toJoinType());
return register(rel, newJoin, mapOldToNewOutputs, corDefOutputs);
}
use of org.apache.beam.vendor.calcite.v1_28_0.org.apache.calcite.rel.type.RelDataTypeField in project calcite by apache.
the class RelBuilder method field.
/**
* As {@link #field(int, int, int)}, but if {@code alias} is true, the method
* may apply an alias to make sure that the field has the same name as in the
* input frame. If no alias is applied the expression is definitely a
* {@link RexInputRef}.
*/
private RexNode field(int inputCount, int inputOrdinal, int fieldOrdinal, boolean alias) {
final Frame frame = peek_(inputCount, inputOrdinal);
final RelNode input = frame.rel;
final RelDataType rowType = input.getRowType();
if (fieldOrdinal < 0 || fieldOrdinal > rowType.getFieldCount()) {
throw new IllegalArgumentException("field ordinal [" + fieldOrdinal + "] out of range; input fields are: " + rowType.getFieldNames());
}
final RelDataTypeField field = rowType.getFieldList().get(fieldOrdinal);
final int offset = inputOffset(inputCount, inputOrdinal);
final RexInputRef ref = cluster.getRexBuilder().makeInputRef(field.getType(), offset + fieldOrdinal);
final RelDataTypeField aliasField = frame.fields().get(fieldOrdinal);
if (!alias || field.getName().equals(aliasField.getName())) {
return ref;
} else {
return alias(ref, aliasField.getName());
}
}
use of org.apache.beam.vendor.calcite.v1_28_0.org.apache.calcite.rel.type.RelDataTypeField in project calcite by apache.
the class RelBuilder method match.
/**
* Creates a {@link org.apache.calcite.rel.core.Match}.
*/
public RelBuilder match(RexNode pattern, boolean strictStart, boolean strictEnd, Map<String, RexNode> patternDefinitions, Iterable<? extends RexNode> measureList, RexNode after, Map<String, ? extends SortedSet<String>> subsets, boolean allRows, Iterable<? extends RexNode> partitionKeys, Iterable<? extends RexNode> orderKeys, RexNode interval) {
final List<RelFieldCollation> fieldCollations = new ArrayList<>();
for (RexNode orderKey : orderKeys) {
final RelFieldCollation.Direction direction;
switch(orderKey.getKind()) {
case DESCENDING:
direction = RelFieldCollation.Direction.DESCENDING;
orderKey = ((RexCall) orderKey).getOperands().get(0);
break;
case NULLS_FIRST:
case NULLS_LAST:
throw new AssertionError();
default:
direction = RelFieldCollation.Direction.ASCENDING;
break;
}
final RelFieldCollation.NullDirection nullDirection = direction.defaultNullDirection();
final RexInputRef ref = (RexInputRef) orderKey;
fieldCollations.add(new RelFieldCollation(ref.getIndex(), direction, nullDirection));
}
final RelDataTypeFactory.Builder typeBuilder = cluster.getTypeFactory().builder();
for (RexNode partitionKey : partitionKeys) {
typeBuilder.add(partitionKey.toString(), partitionKey.getType());
}
if (allRows) {
for (RexNode orderKey : orderKeys) {
if (!typeBuilder.nameExists(orderKey.toString())) {
typeBuilder.add(orderKey.toString(), orderKey.getType());
}
}
final RelDataType inputRowType = peek().getRowType();
for (RelDataTypeField fs : inputRowType.getFieldList()) {
if (!typeBuilder.nameExists(fs.getName())) {
typeBuilder.add(fs);
}
}
}
final ImmutableMap.Builder<String, RexNode> measures = ImmutableMap.builder();
for (RexNode measure : measureList) {
List<RexNode> operands = ((RexCall) measure).getOperands();
String alias = operands.get(1).toString();
typeBuilder.add(alias, operands.get(0).getType());
measures.put(alias, operands.get(0));
}
final RelNode match = matchFactory.createMatch(peek(), pattern, typeBuilder.build(), strictStart, strictEnd, patternDefinitions, measures.build(), after, subsets, allRows, ImmutableList.copyOf(partitionKeys), RelCollations.of(fieldCollations), interval);
stack.push(new Frame(match));
return this;
}
use of org.apache.beam.vendor.calcite.v1_28_0.org.apache.calcite.rel.type.RelDataTypeField in project calcite by apache.
the class RelFieldTrimmer method trimFields.
/**
* Variant of {@link #trimFields(RelNode, ImmutableBitSet, Set)} for
* {@link org.apache.calcite.rel.logical.LogicalFilter}.
*/
public TrimResult trimFields(Filter filter, ImmutableBitSet fieldsUsed, Set<RelDataTypeField> extraFields) {
final RelDataType rowType = filter.getRowType();
final int fieldCount = rowType.getFieldCount();
final RexNode conditionExpr = filter.getCondition();
final RelNode input = filter.getInput();
// We use the fields used by the consumer, plus any fields used in the
// filter.
final Set<RelDataTypeField> inputExtraFields = new LinkedHashSet<>(extraFields);
RelOptUtil.InputFinder inputFinder = new RelOptUtil.InputFinder(inputExtraFields);
inputFinder.inputBitSet.addAll(fieldsUsed);
conditionExpr.accept(inputFinder);
final ImmutableBitSet inputFieldsUsed = inputFinder.inputBitSet.build();
// Create input with trimmed columns.
TrimResult trimResult = trimChild(filter, input, inputFieldsUsed, inputExtraFields);
RelNode newInput = trimResult.left;
final Mapping inputMapping = trimResult.right;
// there's nothing we can do.
if (newInput == input && fieldsUsed.cardinality() == fieldCount) {
return result(filter, Mappings.createIdentity(fieldCount));
}
// Build new project expressions, and populate the mapping.
final RexVisitor<RexNode> shuttle = new RexPermuteInputsShuttle(inputMapping, newInput);
RexNode newConditionExpr = conditionExpr.accept(shuttle);
// Use copy rather than relBuilder so that correlating variables get set.
relBuilder.push(filter.copy(filter.getTraitSet(), newInput, newConditionExpr));
// needs them for its condition.
return result(relBuilder.build(), inputMapping);
}
Aggregations