Skip to content

Instantly share code, notes, and snippets.

@mbwhite
Created December 8, 2025 15:09
Show Gist options
  • Select an option

  • Save mbwhite/4899dfd959839a6eedd6ee1542c9fb08 to your computer and use it in GitHub Desktop.

Select an option

Save mbwhite/4899dfd959839a6eedd6ee1542c9fb08 to your computer and use it in GitHub Desktop.
Calcite Optimizer Removes Correlation Variable Context
class FromSqlTests {
@Test
void calciterelNode() {
try {
final String sql = """
SELECT
P.P_PARTKEY
FROM
PART P
JOIN PARTSUPP PS ON P.P_PARTKEY = PS.PS_PARTKEY
WHERE
PS.PS_SUPPLYCOST = (
SELECT
MIN(PS_INNER.PS_SUPPLYCOST)
FROM
PARTSUPP PS_INNER
WHERE
PS_INNER.PS_PARTKEY = P.P_PARTKEY
)
""";
final SqlParser.Config parserCfg = SqlParser.config()
.withCaseSensitive(false)
.withConformance(SqlConformanceEnum.DEFAULT);
SqlNode parsed;
parsed = SqlParser.create(sql, parserCfg).parseQuery();
final CatalogReader tpchCatalogReader = Schemas.fromTpcH();
final RelDataTypeFactory typeFactory = new JavaTypeFactoryImpl();
final SqlValidator validator = SqlValidatorUtil.newValidator(
SqlStdOperatorTable.instance(), // built-in operators
tpchCatalogReader, // our schema/catalog
typeFactory,
SqlValidator.Config.DEFAULT
.withConformance(SqlConformanceEnum.DEFAULT)
.withIdentifierExpansion(true) // expands aliases / qualifiers
);
final SqlNode validated = validator.validate(parsed);
System.out.println("SqlNode Parsed to >>");
System.out.println(validated.toString());
final HepProgram program = HepProgram.builder()
.build();
final HepPlanner planner = new HepPlanner(program);
final RelOptCluster cluster = RelOptCluster.create(planner, new RexBuilder(typeFactory));
final SqlToRelConverter.Config convertCfg = SqlToRelConverter.config()
.withExpand(false); // typical defaults
final SqlToRelConverter toRel = new SqlToRelConverter(
null, // ViewExpander (null if unused)
validator,
tpchCatalogReader, // same catalog reader
cluster,
StandardConvertletTable.INSTANCE,
convertCfg);
final RelRoot relRoot = toRel.convertQuery(validated, false, true);
final RelNode rel = relRoot.project(); // drop hidden sort keys if needed
System.out.println("-----");
System.out.println("Converted to CalciteRelNodes");
System.out.println(rel.explain()); // print logical plan
final HepProgram hepProgram = HepProgram.builder()
.addRuleInstance(CoreRules.FILTER_INTO_JOIN)
// .addRuleInstance(CoreRules.FILTER_REDUCE_EXPRESSIONS)
// .addRuleInstance(CoreRules.FILTER_SCAN)
.build();
// Build a copy hook to keep correlation maps aligned as nodes are copied
Function2<RelNode, RelNode, Void> onCopyHook = (oldNode, newNode) -> {
// Mimics RelDecorrelator#createCopyHook: update CorelMap entries
// when a LogicalCorrelate or a referencing node is replaced.
// (See RelDecorrelator source for exact logic.)
return null;
};
final HepPlanner hepPlanner = new HepPlanner(hepProgram, null, true, onCopyHook,RelOptCostImpl.FACTORY);
hepPlanner.setRoot(relRoot.rel);
final RelNode bestRelNode = hepPlanner.findBestExp();
final RelRoot optimizedf = RelRoot.of(bestRelNode, relRoot.kind);
System.out.println("-----");
System.out.println("Optimised CalciteRelNodes");
System.out.println(optimizedf.rel.explain()); // print logical plan
SqlDialect dialect = AnsiSqlDialect.DEFAULT;
// 2) Convert RelRoot -> SqlNode
RelToSqlConverter converter = new RelToSqlConverter(dialect);
// visitRoot handles RelRoot; for a bare RelNode, use visitChild(0, rel)
SqlNode sqlNode = converter.visitRoot(optimizedf.rel).asStatement();
System.out.println(sqlNode);
assert (true);
} catch (SqlParseException e) {
e.printStackTrace();
// throw new RuntimeException(e);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment