use of org.apache.calcite.rex.RexInputRef in project calcite by apache.
the class JoinToCorrelateRule method onMatch.
public void onMatch(RelOptRuleCall call) {
assert matches(call);
final LogicalJoin join = call.rel(0);
RelNode right = join.getRight();
final RelNode left = join.getLeft();
final int leftFieldCount = left.getRowType().getFieldCount();
final RelOptCluster cluster = join.getCluster();
final RexBuilder rexBuilder = cluster.getRexBuilder();
final RelBuilder relBuilder = call.builder();
final CorrelationId correlationId = cluster.createCorrel();
final RexNode corrVar = rexBuilder.makeCorrel(left.getRowType(), correlationId);
final ImmutableBitSet.Builder requiredColumns = ImmutableBitSet.builder();
// Replace all references of left input with FieldAccess(corrVar, field)
final RexNode joinCondition = join.getCondition().accept(new RexShuttle() {
@Override
public RexNode visitInputRef(RexInputRef input) {
int field = input.getIndex();
if (field >= leftFieldCount) {
return rexBuilder.makeInputRef(input.getType(), input.getIndex() - leftFieldCount);
}
requiredColumns.set(field);
return rexBuilder.makeFieldAccess(corrVar, field);
}
});
relBuilder.push(right).filter(joinCondition);
RelNode newRel = LogicalCorrelate.create(left, relBuilder.build(), correlationId, requiredColumns.build(), SemiJoinType.of(join.getJoinType()));
call.transformTo(newRel);
}
use of org.apache.calcite.rex.RexInputRef in project calcite by apache.
the class CalcRelSplitter method chooseLevels.
/**
* Figures out which expressions to calculate at which level.
*
* @param exprs Array of expressions
* @param conditionOrdinal Ordinal of the condition expression, or -1 if no
* condition
* @param exprLevels Level ordinal for each expression (output)
* @param levelTypeOrdinals The type of each level (output)
* @return Number of levels required
*/
private int chooseLevels(final RexNode[] exprs, int conditionOrdinal, int[] exprLevels, int[] levelTypeOrdinals) {
final int inputFieldCount = program.getInputRowType().getFieldCount();
int levelCount = 0;
final MaxInputFinder maxInputFinder = new MaxInputFinder(exprLevels);
boolean[] relTypesPossibleForTopLevel = new boolean[relTypes.length];
Arrays.fill(relTypesPossibleForTopLevel, true);
// Compute the order in which to visit expressions.
final List<Set<Integer>> cohorts = getCohorts();
final List<Integer> permutation = computeTopologicalOrdering(exprs, cohorts);
for (int i : permutation) {
RexNode expr = exprs[i];
final boolean condition = i == conditionOrdinal;
if (i < inputFieldCount) {
assert expr instanceof RexInputRef;
exprLevels[i] = -1;
continue;
}
// Deduce the minimum level of the expression. An expression must
// be at a level greater than or equal to all of its inputs.
int level = maxInputFinder.maxInputFor(expr);
// If the expression is in a cohort, it can occur no lower than the
// levels of other expressions in the same cohort.
Set<Integer> cohort = findCohort(cohorts, i);
if (cohort != null) {
for (Integer exprOrdinal : cohort) {
if (exprOrdinal == i) {
// of effort to repeat.
continue;
}
final RexNode cohortExpr = exprs[exprOrdinal];
int cohortLevel = maxInputFinder.maxInputFor(cohortExpr);
if (cohortLevel > level) {
level = cohortLevel;
}
}
}
// If that is not possible, try to implement it at higher levels.
levelLoop: for (; ; ++level) {
if (level >= levelCount) {
// This is a new level. We can use any type we like.
for (int relTypeOrdinal = 0; relTypeOrdinal < relTypes.length; relTypeOrdinal++) {
if (!relTypesPossibleForTopLevel[relTypeOrdinal]) {
continue;
}
if (relTypes[relTypeOrdinal].canImplement(expr, condition)) {
// Success. We have found a type where we can
// implement this expression.
exprLevels[i] = level;
levelTypeOrdinals[level] = relTypeOrdinal;
assert (level == 0) || (levelTypeOrdinals[level - 1] != levelTypeOrdinals[level]) : "successive levels of same type";
// Previous reltypes are not possible.
for (int j = 0; j < relTypeOrdinal; ++j) {
relTypesPossibleForTopLevel[j] = false;
}
// Successive reltypes may be possible.
for (int j = relTypeOrdinal + 1; j < relTypes.length; ++j) {
if (relTypesPossibleForTopLevel[j]) {
relTypesPossibleForTopLevel[j] = relTypes[j].canImplement(expr, condition);
}
}
// Move to next level.
levelTypeOrdinals[levelCount] = firstSet(relTypesPossibleForTopLevel);
++levelCount;
Arrays.fill(relTypesPossibleForTopLevel, true);
break levelLoop;
}
}
// level, with all options open?
if (count(relTypesPossibleForTopLevel) >= relTypes.length) {
// Cannot implement for any type.
throw new AssertionError("cannot implement " + expr);
}
levelTypeOrdinals[levelCount] = firstSet(relTypesPossibleForTopLevel);
++levelCount;
Arrays.fill(relTypesPossibleForTopLevel, true);
} else {
final int levelTypeOrdinal = levelTypeOrdinals[level];
if (!relTypes[levelTypeOrdinal].canImplement(expr, condition)) {
// continue to next level.
continue;
}
exprLevels[i] = level;
break;
}
}
}
if (levelCount > 0) {
// implemented.
assert "CalcRelType".equals(relTypes[0].name) : "The first RelType should be CalcRelType for proper RexLiteral" + " implementation at the last level, got " + relTypes[0].name;
if (levelTypeOrdinals[levelCount - 1] != 0) {
levelCount++;
}
}
return levelCount;
}
use of org.apache.calcite.rex.RexInputRef in project calcite by apache.
the class LoptSemiJoinOptimizer method isSuitableFilter.
/**
* Determines if a join filter can be used with a semijoin against a
* specified fact table. A suitable filter is of the form "factable.col1 =
* dimTable.col2".
*
* @param multiJoin join factors being optimized
* @param joinFilter filter to be analyzed
* @param factIdx index corresponding to the fact table
*
* @return index of corresponding dimension table if the filter is
* appropriate; otherwise -1 is returned
*/
private int isSuitableFilter(LoptMultiJoin multiJoin, RexNode joinFilter, int factIdx) {
// RexInputRefs
switch(joinFilter.getKind()) {
case EQUALS:
break;
default:
return -1;
}
List<RexNode> operands = ((RexCall) joinFilter).getOperands();
if (!(operands.get(0) instanceof RexInputRef) || !(operands.get(1) instanceof RexInputRef)) {
return -1;
}
// filter is suitable if each side of the filter only contains a
// single factor reference and one side references the fact table and
// the other references the dimension table; since we know this is
// a join filter and we've already verified that the operands are
// RexInputRefs, verify that the factors belong to the fact and
// dimension table
ImmutableBitSet joinRefs = multiJoin.getFactorsRefByJoinFilter(joinFilter);
assert joinRefs.cardinality() == 2;
int factor1 = joinRefs.nextSetBit(0);
int factor2 = joinRefs.nextSetBit(factor1 + 1);
if (factor1 == factIdx) {
return factor2;
}
if (factor2 == factIdx) {
return factor1;
}
return -1;
}
use of org.apache.calcite.rex.RexInputRef in project calcite by apache.
the class SqlImplementor method convertConditionToSqlNode.
/**
* Converts a {@link RexNode} condition into a {@link SqlNode}.
*
* @param node Join condition
* @param leftContext Left context
* @param rightContext Right context
* @param leftFieldCount Number of fields on left result
* @return SqlNode that represents the condition
*/
public static SqlNode convertConditionToSqlNode(RexNode node, Context leftContext, Context rightContext, int leftFieldCount) {
if (node.isAlwaysTrue()) {
return SqlLiteral.createBoolean(true, POS);
}
if (node.isAlwaysFalse()) {
return SqlLiteral.createBoolean(false, POS);
}
if (!(node instanceof RexCall)) {
throw new AssertionError(node);
}
final List<RexNode> operands;
final SqlOperator op;
final Context joinContext;
switch(node.getKind()) {
case AND:
case OR:
operands = ((RexCall) node).getOperands();
op = ((RexCall) node).getOperator();
SqlNode sqlCondition = null;
for (RexNode operand : operands) {
SqlNode x = convertConditionToSqlNode(operand, leftContext, rightContext, leftFieldCount);
if (sqlCondition == null) {
sqlCondition = x;
} else {
sqlCondition = op.createCall(POS, sqlCondition, x);
}
}
return sqlCondition;
case EQUALS:
case IS_NOT_DISTINCT_FROM:
case NOT_EQUALS:
case GREATER_THAN:
case GREATER_THAN_OR_EQUAL:
case LESS_THAN:
case LESS_THAN_OR_EQUAL:
node = stripCastFromString(node);
operands = ((RexCall) node).getOperands();
op = ((RexCall) node).getOperator();
if (operands.size() == 2 && operands.get(0) instanceof RexInputRef && operands.get(1) instanceof RexInputRef) {
final RexInputRef op0 = (RexInputRef) operands.get(0);
final RexInputRef op1 = (RexInputRef) operands.get(1);
if (op0.getIndex() < leftFieldCount && op1.getIndex() >= leftFieldCount) {
// Arguments were of form 'op0 = op1'
return op.createCall(POS, leftContext.field(op0.getIndex()), rightContext.field(op1.getIndex() - leftFieldCount));
}
if (op1.getIndex() < leftFieldCount && op0.getIndex() >= leftFieldCount) {
// Arguments were of form 'op1 = op0'
return reverseOperatorDirection(op).createCall(POS, leftContext.field(op1.getIndex()), rightContext.field(op0.getIndex() - leftFieldCount));
}
}
joinContext = leftContext.implementor().joinContext(leftContext, rightContext);
return joinContext.toSql(null, node);
case IS_NULL:
case IS_NOT_NULL:
operands = ((RexCall) node).getOperands();
if (operands.size() == 1 && operands.get(0) instanceof RexInputRef) {
op = ((RexCall) node).getOperator();
final RexInputRef op0 = (RexInputRef) operands.get(0);
if (op0.getIndex() < leftFieldCount) {
return op.createCall(POS, leftContext.field(op0.getIndex()));
} else {
return op.createCall(POS, rightContext.field(op0.getIndex() - leftFieldCount));
}
}
joinContext = leftContext.implementor().joinContext(leftContext, rightContext);
return joinContext.toSql(null, node);
default:
throw new AssertionError(node);
}
}
use of org.apache.calcite.rex.RexInputRef in project calcite by apache.
the class SqlToRelConverter method convertMerge.
private RelNode convertMerge(SqlMerge call) {
RelOptTable targetTable = getTargetTable(call);
// convert update column list from SqlIdentifier to String
final List<String> targetColumnNameList = new ArrayList<>();
final RelDataType targetRowType = targetTable.getRowType();
SqlUpdate updateCall = call.getUpdateCall();
if (updateCall != null) {
for (SqlNode targetColumn : updateCall.getTargetColumnList()) {
SqlIdentifier id = (SqlIdentifier) targetColumn;
RelDataTypeField field = SqlValidatorUtil.getTargetField(targetRowType, typeFactory, id, catalogReader, targetTable);
assert field != null : "column " + id.toString() + " not found";
targetColumnNameList.add(field.getName());
}
}
// replace the projection of the source select with a
// projection that contains the following:
// 1) the expressions corresponding to the new insert row (if there is
// an insert)
// 2) all columns from the target table (if there is an update)
// 3) the set expressions in the update call (if there is an update)
// first, convert the merge's source select to construct the columns
// from the target table and the set expressions in the update call
RelNode mergeSourceRel = convertSelect(call.getSourceSelect(), false);
// then, convert the insert statement so we can get the insert
// values expressions
SqlInsert insertCall = call.getInsertCall();
int nLevel1Exprs = 0;
List<RexNode> level1InsertExprs = null;
List<RexNode> level2InsertExprs = null;
if (insertCall != null) {
RelNode insertRel = convertInsert(insertCall);
// if there are 2 level of projections in the insert source, combine
// them into a single project; level1 refers to the topmost project;
// the level1 projection contains references to the level2
// expressions, except in the case where no target expression was
// provided, in which case, the expression is the default value for
// the column; or if the expressions directly map to the source
// table
level1InsertExprs = ((LogicalProject) insertRel.getInput(0)).getProjects();
if (insertRel.getInput(0).getInput(0) instanceof LogicalProject) {
level2InsertExprs = ((LogicalProject) insertRel.getInput(0).getInput(0)).getProjects();
}
nLevel1Exprs = level1InsertExprs.size();
}
LogicalJoin join = (LogicalJoin) mergeSourceRel.getInput(0);
int nSourceFields = join.getLeft().getRowType().getFieldCount();
final List<RexNode> projects = new ArrayList<>();
for (int level1Idx = 0; level1Idx < nLevel1Exprs; level1Idx++) {
if ((level2InsertExprs != null) && (level1InsertExprs.get(level1Idx) instanceof RexInputRef)) {
int level2Idx = ((RexInputRef) level1InsertExprs.get(level1Idx)).getIndex();
projects.add(level2InsertExprs.get(level2Idx));
} else {
projects.add(level1InsertExprs.get(level1Idx));
}
}
if (updateCall != null) {
final LogicalProject project = (LogicalProject) mergeSourceRel;
projects.addAll(Util.skip(project.getProjects(), nSourceFields));
}
relBuilder.push(join).project(projects);
return LogicalTableModify.create(targetTable, catalogReader, relBuilder.build(), LogicalTableModify.Operation.MERGE, targetColumnNameList, null, false);
}
Aggregations