Source:
public void onMatch(RelOptRuleCall call) { FlinkLogicalWatermarkAssigner watermarkAssigner = call.rel(0); FlinkLogicalCalc calc = call.rel(1); RexProgram originProgram = calc.getProgram(); List<RexNode> projectList = originProgram.getProjectList().stream() .map(originProgram::expandLocalRef) .collect(Collectors.toList()); RexNode computedColumn = projectList.get(watermarkAssigner.rowtimeFieldIndex()); RexNode newWatermarkExpr = watermarkAssigner.watermarkExpr().accept(new RexShuttle() { @Override public RexNode visitInputRef(RexInputRef inputRef) { if (inputRef.getIndex() == watermarkAssigner.rowtimeFieldIndex()) { return computedColumn; } else { return inputRef; } } }); FlinkLogicalTableSourceScan newScan = getNewScan(watermarkAssigner, newWatermarkExpr, call.rel(2), ((FlinkContext) call.getPlanner().getContext()).getTableConfig()); FlinkTypeFactory typeFactory = (FlinkTypeFactory) watermarkAssigner.getCluster().getTypeFactory(); RexBuilder builder = call.builder().getRexBuilder(); RexNode newComputedColumn = builder.makeReinterpretCast( typeFactory.createRowtimeIndicatorType(computedColumn.getType().isNullable()), computedColumn, null); RexProgramBuilder programBuilder = new RexProgramBuilder(newScan.getRowType(), builder); for (int i = 0; i < projectList.size(); i++) { Pair<RexLocalRef, String> rexLocalRefStringPair = originProgram.getNamedProjects().get(i); if (i == watermarkAssigner.rowtimeFieldIndex()) { programBuilder.addProject(newComputedColumn, rexLocalRefStringPair.right); } else { programBuilder.addProject(projectList.get(i), rexLocalRefStringPair.right); } } if (originProgram.getCondition() != null) { programBuilder.addCondition(originProgram.expandLocalRef(originProgram.getCondition())); } FlinkLogicalCalc newCalc = FlinkLogicalCalc.create(newScan, programBuilder.getProgram()); call.transformTo(newCalc); }

Target:
public void onMatch(RelOptRuleCall call) { FlinkLogicalWatermarkAssigner watermarkAssigner = call.rel(0); FlinkLogicalCalc calc = call.rel(1); RexProgram originProgram = calc.getProgram(); List<RexNode> projectList = originProgram.getProjectList().stream() .map(originProgram::expandLocalRef) .collect(Collectors.toList()); RexNode rowTimeColumn = projectList.get(watermarkAssigner.rowtimeFieldIndex()); RexNode newWatermarkExpr = watermarkAssigner.watermarkExpr().accept(new RexShuttle() { @Override public RexNode visitInputRef(RexInputRef inputRef) { return projectList.get(inputRef.getIndex()); } }); FlinkLogicalTableSourceScan newScan = getNewScan( watermarkAssigner, newWatermarkExpr, call.rel(2), ((FlinkContext) call.getPlanner().getContext()).getTableConfig(), false); FlinkTypeFactory typeFactory = (FlinkTypeFactory) watermarkAssigner.getCluster().getTypeFactory(); RexBuilder builder = call.builder().getRexBuilder(); RexNode newRowTimeColumn = builder.makeReinterpretCast( typeFactory.createRowtimeIndicatorType(rowTimeColumn.getType().isNullable()), rowTimeColumn, null); RexProgramBuilder programBuilder = new RexProgramBuilder(newScan.getRowType(), builder); List<String> outputFieldNames = originProgram.getOutputRowType().getFieldNames(); for (int i = 0; i < projectList.size(); i++) { if (i == watermarkAssigner.rowtimeFieldIndex()) { programBuilder.addProject(newRowTimeColumn, outputFieldNames.get(i)); } else { programBuilder.addProject(projectList.get(i), outputFieldNames.get(i)); } } if (originProgram.getCondition() != null) { programBuilder.addCondition(originProgram.expandLocalRef(originProgram.getCondition())); } FlinkLogicalCalc newCalc = FlinkLogicalCalc.create(newScan, programBuilder.getProgram()); call.transformTo(newCalc); }