use of org.apache.calcite.rex.RexInputRef 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.calcite.rex.RexInputRef 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.calcite.rex.RexInputRef in project calcite by apache.
the class RelBuilder method inferAlias.
/**
* Infers the alias of an expression.
*
* <p>If the expression was created by {@link #alias}, replaces the expression
* in the project list.
*/
private String inferAlias(List<RexNode> exprList, RexNode expr) {
switch(expr.getKind()) {
case INPUT_REF:
final RexInputRef ref = (RexInputRef) expr;
return stack.peek().fields.get(ref.getIndex()).getValue().getName();
case CAST:
return inferAlias(exprList, ((RexCall) expr).getOperands().get(0));
case AS:
final RexCall call = (RexCall) expr;
for (; ; ) {
final int i = exprList.indexOf(expr);
if (i < 0) {
break;
}
exprList.set(i, call.getOperands().get(0));
}
return ((NlsString) ((RexLiteral) call.getOperands().get(1)).getValue()).getValue();
default:
return null;
}
}
use of org.apache.calcite.rex.RexInputRef 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.calcite.rex.RexInputRef in project calcite by apache.
the class RelStructuredTypeFlattener method flattenProjection.
private void flattenProjection(RewriteRexShuttle shuttle, RexNode exp, String fieldName, List<Pair<RexNode, String>> flattenedExps) {
if (exp.getType().isStruct()) {
if (exp instanceof RexInputRef) {
RexInputRef inputRef = (RexInputRef) exp;
int newOffset = getNewForOldInput(inputRef.getIndex());
// expand to range
RelDataType flattenedType = SqlTypeUtil.flattenRecordType(rexBuilder.getTypeFactory(), exp.getType(), null);
List<RelDataTypeField> fieldList = flattenedType.getFieldList();
int n = fieldList.size();
for (int j = 0; j < n; ++j) {
RelDataTypeField field = fieldList.get(j);
flattenedExps.add(Pair.<RexNode, String>of(new RexInputRef(newOffset + j, field.getType()), fieldName));
}
} else if (isConstructor(exp) || exp.isA(SqlKind.CAST)) {
// REVIEW jvs 27-Feb-2005: for cast, see corresponding note
// in RewriteRexShuttle
RexCall call = (RexCall) exp;
if (exp.isA(SqlKind.NEW_SPECIFICATION)) {
// For object constructors, prepend a FALSE null
// indicator.
flattenedExps.add(Pair.<RexNode, String>of(rexBuilder.makeLiteral(false), fieldName));
} else if (exp.isA(SqlKind.CAST)) {
if (RexLiteral.isNullLiteral(((RexCall) exp).operands.get(0))) {
// Translate CAST(NULL AS UDT) into
// the correct number of null fields.
flattenNullLiteral(exp.getType(), flattenedExps);
return;
}
}
flattenProjections(new RewriteRexShuttle(), call.getOperands(), Collections.<String>nCopies(call.getOperands().size(), null), fieldName, flattenedExps);
} else if (exp instanceof RexCall) {
// NOTE jvs 10-Feb-2005: This is a lame hack to keep special
// functions which return row types working.
int j = 0;
RexNode newExp = exp;
List<RexNode> oldOperands = ((RexCall) exp).getOperands();
if (oldOperands.get(0) instanceof RexInputRef) {
RexInputRef inputRef = (RexInputRef) oldOperands.get(0);
int newOffset = getNewForOldInput(inputRef.getIndex());
newExp = rexBuilder.makeCall(exp.getType(), ((RexCall) exp).getOperator(), ImmutableList.of(rexBuilder.makeInputRef(inputRef.getType(), newOffset), oldOperands.get(1)));
}
for (RelDataTypeField field : newExp.getType().getFieldList()) {
flattenedExps.add(Pair.of(rexBuilder.makeFieldAccess(newExp, field.getIndex()), fieldName + "$" + (j++)));
}
} else {
throw Util.needToImplement(exp);
}
} else {
flattenedExps.add(Pair.of(exp.accept(shuttle), fieldName));
}
}
Aggregations