use of org.apache.calcite.rex.RexProgram in project flink by apache.
the class PushFilterInCalcIntoTableSourceScanRule method matches.
@Override
public boolean matches(RelOptRuleCall call) {
if (!super.matches(call)) {
return false;
}
FlinkLogicalCalc calc = call.rel(0);
RexProgram originProgram = calc.getProgram();
if (originProgram.getCondition() == null) {
return false;
}
FlinkLogicalTableSourceScan scan = call.rel(1);
TableSourceTable tableSourceTable = scan.getTable().unwrap(TableSourceTable.class);
// we can not push filter twice
return canPushdownFilter(tableSourceTable);
}
use of org.apache.calcite.rex.RexProgram in project flink by apache.
the class PushFilterInCalcIntoTableSourceScanRule method pushFilterIntoScan.
private void pushFilterIntoScan(RelOptRuleCall call, Calc calc, FlinkLogicalTableSourceScan scan, FlinkPreparingTableBase relOptTable) {
RexProgram originProgram = calc.getProgram();
RelBuilder relBuilder = call.builder();
Tuple2<RexNode[], RexNode[]> extractedPredicates = extractPredicates(originProgram.getInputRowType().getFieldNames().toArray(new String[0]), originProgram.expandLocalRef(originProgram.getCondition()), scan, relBuilder.getRexBuilder());
RexNode[] convertiblePredicates = extractedPredicates._1;
RexNode[] unconvertedPredicates = extractedPredicates._2;
if (convertiblePredicates.length == 0) {
// no condition can be translated to expression
return;
}
Tuple2<SupportsFilterPushDown.Result, TableSourceTable> pushdownResultWithScan = resolveFiltersAndCreateTableSourceTable(convertiblePredicates, relOptTable.unwrap(TableSourceTable.class), scan, relBuilder);
SupportsFilterPushDown.Result result = pushdownResultWithScan._1;
TableSourceTable tableSourceTable = pushdownResultWithScan._2;
FlinkLogicalTableSourceScan newScan = FlinkLogicalTableSourceScan.create(scan.getCluster(), scan.getHints(), tableSourceTable);
// build new calc program
RexProgramBuilder programBuilder = RexProgramBuilder.forProgram(originProgram, call.builder().getRexBuilder(), true);
programBuilder.clearCondition();
if (!result.getRemainingFilters().isEmpty() || unconvertedPredicates.length != 0) {
RexNode remainingCondition = createRemainingCondition(relBuilder, result.getRemainingFilters(), unconvertedPredicates);
RexNode simplifiedRemainingCondition = FlinkRexUtil.simplify(relBuilder.getRexBuilder(), remainingCondition, calc.getCluster().getPlanner().getExecutor());
programBuilder.addCondition(simplifiedRemainingCondition);
}
RexProgram program = programBuilder.getProgram();
if (program.isTrivial()) {
call.transformTo(newScan);
} else {
FlinkLogicalCalc newCalc = FlinkLogicalCalc.create(newScan, program);
call.transformTo(newCalc);
}
}
use of org.apache.calcite.rex.RexProgram in project flink by apache.
the class RelTimeIndicatorConverter method visitCalc.
private RelNode visitCalc(FlinkLogicalCalc calc) {
// visit children and update inputs
RelNode newInput = calc.getInput().accept(this);
RexProgram program = calc.getProgram();
// check if input field contains time indicator type
// materialize field if no time indicator is present anymore
// if input field is already materialized, change to timestamp type
RexTimeIndicatorMaterializer materializer = new RexTimeIndicatorMaterializer(newInput);
List<RexNode> newProjects = program.getProjectList().stream().map(project -> program.expandLocalRef(project).accept(materializer)).collect(Collectors.toList());
// materialize condition due to filter will validate condition type
RexNode newCondition = null;
if (program.getCondition() != null) {
newCondition = program.expandLocalRef(program.getCondition()).accept(materializer);
}
RexProgram newProgram = RexProgram.create(newInput.getRowType(), newProjects, newCondition, program.getOutputRowType().getFieldNames(), rexBuilder);
return calc.copy(calc.getTraitSet(), newInput, newProgram);
}
use of org.apache.calcite.rex.RexProgram in project flink by apache.
the class RelTimeIndicatorConverter method createCalcToMaterializeTimeIndicators.
private RelNode createCalcToMaterializeTimeIndicators(RelNode input, Set<Integer> refIndices) {
// create new calc
List<RexNode> projects = input.getRowType().getFieldList().stream().map(field -> {
RexNode project = new RexInputRef(field.getIndex(), field.getType());
if (refIndices.contains(field.getIndex())) {
project = materializeTimeIndicators(project);
}
return project;
}).collect(Collectors.toList());
RexProgram newProgram = RexProgram.create(input.getRowType(), projects, null, input.getRowType().getFieldNames(), rexBuilder);
return FlinkLogicalCalc.create(input, newProgram);
}
use of org.apache.calcite.rex.RexProgram in project beam by apache.
the class CalcRelSplitter method execute.
// ~ Methods ----------------------------------------------------------------
public RelNode execute() {
// expressions to the left.
assert program.isValid(Litmus.THROW, null);
final List<RexNode> exprList = program.getExprList();
final RexNode[] exprs = exprList.toArray(new RexNode[0]);
assert !RexUtil.containComplexExprs(exprList);
// Figure out what level each expression belongs to.
int[] exprLevels = new int[exprs.length];
// The type of a level is given by
// relTypes[levelTypeOrdinals[level]].
int[] levelTypeOrdinals = new int[exprs.length];
int levelCount = chooseLevels(exprs, -1, exprLevels, levelTypeOrdinals);
// For each expression, figure out which is the highest level where it
// is used.
int[] exprMaxUsingLevelOrdinals = new HighestUsageFinder(exprs, exprLevels).getMaxUsingLevelOrdinals();
// If expressions are used as outputs, mark them as higher than that.
final List<RexLocalRef> projectRefList = program.getProjectList();
final RexLocalRef conditionRef = program.getCondition();
for (RexLocalRef projectRef : projectRefList) {
exprMaxUsingLevelOrdinals[projectRef.getIndex()] = levelCount;
}
if (conditionRef != null) {
exprMaxUsingLevelOrdinals[conditionRef.getIndex()] = levelCount;
}
// Print out what we've got.
if (RULE_LOGGER.isTraceEnabled()) {
traceLevelExpressions(exprs, exprLevels, levelTypeOrdinals, levelCount);
}
// Now build the calcs.
RelNode rel = child;
final int inputFieldCount = program.getInputRowType().getFieldCount();
int[] inputExprOrdinals = identityArray(inputFieldCount);
boolean doneCondition = false;
for (int level = 0; level < levelCount; level++) {
final int[] projectExprOrdinals;
final RelDataType outputRowType;
if (level == (levelCount - 1)) {
outputRowType = program.getOutputRowType();
projectExprOrdinals = new int[projectRefList.size()];
for (int i = 0; i < projectExprOrdinals.length; i++) {
projectExprOrdinals[i] = projectRefList.get(i).getIndex();
}
} else {
outputRowType = null;
// Project the expressions which are computed at this level or
// before, and will be used at later levels.
List<Integer> projectExprOrdinalList = new ArrayList<>();
for (int i = 0; i < exprs.length; i++) {
RexNode expr = exprs[i];
if (expr instanceof RexLiteral) {
// Don't project literals. They are always created in
// the level where they are used.
exprLevels[i] = -1;
continue;
}
if ((exprLevels[i] <= level) && (exprMaxUsingLevelOrdinals[i] > level)) {
projectExprOrdinalList.add(i);
}
}
projectExprOrdinals = Ints.toArray(projectExprOrdinalList);
}
final RelType relType = relTypes[levelTypeOrdinals[level]];
// Can we do the condition this level?
int conditionExprOrdinal = -1;
if ((conditionRef != null) && !doneCondition) {
conditionExprOrdinal = conditionRef.getIndex();
if ((exprLevels[conditionExprOrdinal] > level) || !relType.supportsCondition()) {
// stand down -- we're not ready to do the condition yet
conditionExprOrdinal = -1;
} else {
doneCondition = true;
}
}
RexProgram program1 = createProgramForLevel(level, levelCount, rel.getRowType(), exprs, exprLevels, inputExprOrdinals, projectExprOrdinals, conditionExprOrdinal, outputRowType);
rel = relType.makeRel(cluster, traits, relBuilder, rel, program1);
rel = handle(rel);
// The outputs of this level will be the inputs to the next level.
inputExprOrdinals = projectExprOrdinals;
}
Preconditions.checkArgument(doneCondition || (conditionRef == null), "unhandled condition");
return rel;
}
Aggregations