public final class SemanticIRBuilder extends Object
SemanticProgram from a parsed and resolved
TSelectSqlStatement.
Current scope (after slice 9): SELECT with one or more base-table or
CTE sources, optional WHERE, optional JOIN of base tables with ON
conditions, optional GROUP BY (slice 6), optional WITH clause including
chained CTEs (each CTE sees the ones declared strictly before it),
optional FROM-clause subquery (slice 5), optional row-deduplication via
SELECT DISTINCT or Oracle's SELECT UNIQUE synonym
(slice 8 — see StatementGraph.isDistinct()), optional ORDER BY
over physical column references or column-bearing expressions
(slice 9 — see StatementGraph.getOrderByColumnRefs()).
Expression projections like salary * 2 AS doubled or
a.x + a.y are accepted and marked
OutputColumn.isDerived(); aggregate function calls (slice 6)
are flagged via OutputColumn.isAggregate().
Slice 9 lifts ORDER BY for sort keys that are physical
column references or expressions over them. The collected references
surface as StatementGraph.getOrderByColumnRefs(). Sort
direction (ASC/DESC) and null placement
(NULLS FIRST/NULLS LAST) are presentation metadata
and are not modelled. Ordinal forms (ORDER BY 1) and
projection-alias forms (SELECT id AS x ... ORDER BY x) are
rejected so the dependency information is never silently lost; a
later slice can model output-position references explicitly. The
canonical lineage model (slice 7) deliberately ignores ORDER BY —
sort order changes presentation, not column dependency or row-set
membership.
Row-limit clauses (LIMIT, TOP, OFFSET,
FETCH FIRST) are rejected statement-wide, including the
SQL Server-style ORDER BY ... OFFSET ... FETCH NEXT. With
a row-limit present, ORDER BY ceases to be presentation-only
and starts deciding which rows survive — the canonical-model
exclusion would no longer be sound, so the entire statement is out
of scope until a future slice models row-limit semantics.
Slice 10 lifts HAVING: the predicate's column references
are collected into StatementGraph.getHavingColumnRefs() via
buildHavingColumnRefs(gudusoft.gsqlparser.stmt.TSelectSqlStatement, gudusoft.gsqlparser.ir.semantic.binding.NameBindingProvider). The same visitor pattern as projection
and ORDER BY rejects subqueries (scalar, EXISTS, IN-SELECT, ANY/ALL/
SOME) and window functions before collectColumnRefs(gudusoft.gsqlparser.nodes.TParseTreeNode, gudusoft.gsqlparser.ir.semantic.binding.NameBindingProvider) runs, so
inner-scope refs never leak. HAVING without GROUP BY is supported (the
parser still attaches a TGroupBy node with empty items).
HAVING is row-influence semantically but does not contribute to the
canonical lineage model — see
StatementGraph.getHavingColumnRefs() for why.
Slice 11 lifted uncorrelated scalar subqueries in projection;
scalar bodies are extracted as their own statements via
extractScalarSubqueriesAsStatements(gudusoft.gsqlparser.stmt.TSelectSqlStatement, gudusoft.gsqlparser.ir.semantic.binding.NameBindingProvider, java.util.List<gudusoft.gsqlparser.ir.semantic.StatementGraph>, java.util.List<gudusoft.gsqlparser.ir.semantic.LineageEdge>, java.util.Map<java.lang.String, java.lang.Integer>, gudusoft.gsqlparser.ir.semantic.builder.SemanticIRBuilder.EnclosingScope, boolean) with the synthetic-name
convention <scalar_subquery_<index>>.
Slice 12 lifts set operations (UNION / UNION ALL / INTERSECT /
INTERSECT ALL / MINUS / MINUS ALL / EXCEPT / EXCEPT ALL) at the top
level and as CTE bodies. Each branch becomes its own
StatementGraph with synthetic name
<set_op_branch_<index>>; the outer set-op statement carries
empty relations and lineage edges fan out per-position to
each branch. The flatten descends the left-leaning AST iteratively
(per CLAUDE.md — no recursion on leftStmt/rightStmt).
See buildSetOpProgram(gudusoft.gsqlparser.stmt.TSelectSqlStatement, gudusoft.gsqlparser.ir.semantic.binding.NameBindingProvider, java.util.List<gudusoft.gsqlparser.ir.semantic.StatementGraph>, java.util.List<gudusoft.gsqlparser.ir.semantic.LineageEdge>, java.util.Map<java.lang.String, java.lang.Integer>, java.lang.String, boolean).
Slice 22 lifts window-function frame clauses
(ROWS/RANGE/GROUPS BETWEEN ...); the frame
unit, start bound, and optional end bound are captured in
WindowFrame hung off
WindowSpec.getFrame(). Frame info is presentation-only
(dlineage XML harvests no frame information) and does NOT contribute
to the canonical lineage model — same status as slice-13's
PARTITION BY / OVER ORDER BY refs. Per-bound EXCLUDE clauses
(Netezza-reachable) and non-constant offsets (PG
simple_object_name_t, ANSI parenthesis_t) are still
rejected.
Still rejected: WITH RECURSIVE, DISTINCT ON (...)
and other non-DISTINCT/UNIQUE row-filters,
scalar-body constant-only projections (zero column refs),
correlated scalar subqueries, scalar bodies with
subqueries in WHERE/JOIN ON/GROUP BY, multi-column scalar inner,
scalar subqueries embedded in larger projection expressions including
EXISTS-in-projection, embedded window functions in larger projection
expressions, window functions in scalar-subquery bodies, window
functions in WHERE/JOIN ON/GROUP BY/HAVING/ORDER BY, empty
OVER (), frame clauses with non-constant offsets (PG
simple_object_name_t, ANSI parenthesis_t), frame
EXCLUDE clauses (Netezza-reachable), named windows,
vendor-specific window extensions (FILTER (WHERE ...),
WITHIN GROUP,
KEEP DENSE_RANK, Hive DISTRIBUTE BY/CLUSTER BY/
SORT BY/PARTITION BY ... SORT (...)), non-physical
PARTITION BY / OVER ORDER BY refs (literals,
subqueries, function calls, expressions, expression-alias references),
window function names outside the slice-13 allowlist,
(slice 63 lifts explicit CROSS JOIN, slice 64 lifts
JOIN ... USING (...), and slice 66 lifts NATURAL JOIN
at outer / CTE-body / FROM-subquery-body call sites; all three stay
rejected inside scalar / set-op-branch / set-op-CTE / predicate bodies;
NATURAL additionally requires resolvable catalog metadata on both
sides, with a side-specific reject otherwise), duplicate aliases,
Oracle
ORDER SIBLINGS BY, Teradata ORDER BY ... RESET WHEN,
row-limit clauses, ORDER BY ordinals/aliases, Teradata QUALIFY
clause, set operations nested in FROM-subquery / scalar bodies,
mixed-operator and mixed-_ALL set-op chains, set-op outer
ORDER BY / row-limit clauses, set-op internal-node modifiers, branch
column-count mismatch, set-op branches with FROM-subquery / scalar
projection / their own CTE list, nested WITH on set-op CTE body. The
builder fails fast outside this scope so callers see the unsupported
case immediately rather than receiving a half-built IR.
API status: advanced/preview. This low-level builder requires the
caller to own parsing, Resolver2 configuration, statement dispatch,
catalog/provider consistency, diagnostics, and recovery. New production
integrations should use
SqlSemanticAnalyzer; advanced
integrations should use the atomic buildResult methods rather than
deprecated build compatibility adapters.
| Modifier and Type | Class and Description |
|---|---|
static class |
SemanticIRBuilder.SemanticIRBuildException
Thrown when the input falls outside current builder scope or a
binding fails.
|
| Modifier and Type | Field and Description |
|---|---|
static String |
PREDICATE_BODY_PREFIX
Reserved name prefix for synthetic predicate-subquery body statements
(slice 23 — uncorrelated EXISTS extracted from outer-SELECT JOIN ON).
|
static String |
SCALAR_BODY_PREFIX
Reserved name prefix for synthetic scalar-subquery body
statements (slice 11).
|
static String |
SET_OP_BRANCH_PREFIX
Reserved name prefix for synthetic set-op-branch body statements
(slice 12).
|
public static final String SCALAR_BODY_PREFIX
"<scalar_subquery_<index>>"; the angle brackets ensure
no collision with real CTE names or FROM-clause aliases.
isScalarSyntheticName(String) is the only authorised
detector — both this builder and
SemanticIRProjector.BodyIndexes use it so the convention
lives in one place.public static final String SET_OP_BRANCH_PREFIX
"<set_op_branch_<index>>";
the angle brackets ensure no collision with real CTE names or
FROM-clause aliases. isSetOpBranchSyntheticName(String) is
the only authorised detector — both this builder and
SemanticIRProjector.BodyIndexes use it so the convention
lives in one place (slice-11 process lesson #10 generalised).public static final String PREDICATE_BODY_PREFIX
"<predicate_subquery_<index>>"; the angle
brackets ensure no collision with real CTE names or FROM-clause aliases.
isPredicateSubquerySyntheticName(String) is the only authorised
detector — both this builder and SemanticIRProjector.BodyIndexes
use it so the convention lives in one place.public static boolean isScalarSyntheticName(String name)
name is a synthetic scalar-subquery-body name
created by this builder (slice 11). Used by
SemanticIRProjector.BodyIndexes to skip such bodies when
building the CTE/FROM-subquery name lookup tables — scalar
bodies are reached only via lineage edges, never via relations.
The match is strict: the name must be the full reserved
pattern <scalar_subquery_<digits>>. A real CTE alias
that happens to start with <scalar_subquery_ but
doesn't match the digits-and-closing-bracket suffix is NOT
skipped (codex impl-review round-1 SHOULD 2).
public static boolean isSetOpBranchSyntheticName(String name)
name is a synthetic set-op-branch-body name
created by this builder (slice 12). Used by
SemanticIRProjector.BodyIndexes to skip such bodies when
building the CTE/FROM-subquery name lookup tables — set-op
branches are reached only via lineage edges, never via relations.
The match is strict: the name must be the full reserved
pattern <set_op_branch_<digits>>.
public static boolean isPredicateSubquerySyntheticName(String name)
name is a synthetic predicate-subquery-body name
created by this builder (slice 23). Used by
SemanticIRProjector.BodyIndexes to skip such bodies when
building the CTE/FROM-subquery name lookup tables — predicate-subquery
bodies are unreachable from outer (no relation edge, no lineage edge).public static void clearBuildDiagnostics()
build*Result method and need no clear/drain calls.public static List<Diagnostic> pendingBuildDiagnostics()
public static List<Diagnostic> drainBuildDiagnostics()
SemanticBuildResult directly.public static SemanticBuildResult buildResult(TSelectSqlStatement select, NameBindingProvider provider, SemanticIRBuildOptions options)
options.
Identical to build(TSelectSqlStatement, NameBindingProvider)
except for the knobs in options; pass
SemanticIRBuildOptions.defaults() for the historical behaviour.
With
degrade mode on, an unsupported predicate-subquery body no longer
aborts the call: it becomes an
StatementGraph.KIND_UNANALYZED placeholder plus a
DiagnosticCode.NESTED_BLOCK_UNANALYZED warning, and the host
block's join graph is returned intact.
public static SemanticBuildResult buildResult(TSelectSqlStatement select, NameBindingProvider provider)
@Deprecated public static SemanticProgram build(TSelectSqlStatement select, NameBindingProvider provider, SemanticIRBuildOptions options)
buildResult(gudusoft.gsqlparser.stmt.TSelectSqlStatement, gudusoft.gsqlparser.ir.semantic.binding.NameBindingProvider, gudusoft.gsqlparser.ir.semantic.builder.SemanticIRBuildOptions); this method
publishes the same diagnostics through drainBuildDiagnostics().@Deprecated public static SemanticProgram build(TSelectSqlStatement select, NameBindingProvider provider)
public static SemanticBuildResult buildInsertResult(TInsertSqlStatement insert, NameBindingProvider provider, SemanticIRBuildOptions options)
options; see
build(TSelectSqlStatement, NameBindingProvider, SemanticIRBuildOptions).public static SemanticBuildResult buildInsertResult(TInsertSqlStatement insert, NameBindingProvider provider)
@Deprecated public static SemanticProgram buildInsert(TInsertSqlStatement insert, NameBindingProvider provider, SemanticIRBuildOptions options)
@Deprecated public static SemanticProgram buildInsert(TInsertSqlStatement insert, NameBindingProvider provider)
public static SemanticBuildResult buildCreateTableResult(TCreateTableSqlStatement create, NameBindingProvider provider, SemanticIRBuildOptions options)
options; see
build(TSelectSqlStatement, NameBindingProvider, SemanticIRBuildOptions).public static SemanticBuildResult buildCreateTableResult(TCreateTableSqlStatement create, NameBindingProvider provider)
@Deprecated public static SemanticProgram buildCreateTable(TCreateTableSqlStatement create, NameBindingProvider provider, SemanticIRBuildOptions options)
@Deprecated public static SemanticProgram buildCreateTable(TCreateTableSqlStatement create, NameBindingProvider provider)
public static SemanticBuildResult buildCreateViewResult(TCreateViewSqlStatement create, NameBindingProvider provider, SemanticIRBuildOptions options)
options; see
build(TSelectSqlStatement, NameBindingProvider, SemanticIRBuildOptions).public static SemanticBuildResult buildCreateViewResult(TCreateViewSqlStatement create, NameBindingProvider provider)
@Deprecated public static SemanticProgram buildCreateView(TCreateViewSqlStatement create, NameBindingProvider provider, SemanticIRBuildOptions options)
@Deprecated public static SemanticProgram buildCreateView(TCreateViewSqlStatement create, NameBindingProvider provider)
public static SemanticBuildResult buildUpdateResult(TUpdateSqlStatement update, NameBindingProvider provider, SemanticIRBuildOptions options)
options; see
build(TSelectSqlStatement, NameBindingProvider, SemanticIRBuildOptions).public static SemanticBuildResult buildUpdateResult(TUpdateSqlStatement update, NameBindingProvider provider)
@Deprecated public static SemanticProgram buildUpdate(TUpdateSqlStatement update, NameBindingProvider provider, SemanticIRBuildOptions options)
@Deprecated public static SemanticProgram buildUpdate(TUpdateSqlStatement update, NameBindingProvider provider)
public static SemanticBuildResult buildDeleteResult(TDeleteSqlStatement delete, NameBindingProvider provider, SemanticIRBuildOptions options)
options; see
build(TSelectSqlStatement, NameBindingProvider, SemanticIRBuildOptions).public static SemanticBuildResult buildDeleteResult(TDeleteSqlStatement delete, NameBindingProvider provider)
@Deprecated public static SemanticProgram buildDelete(TDeleteSqlStatement delete, NameBindingProvider provider, SemanticIRBuildOptions options)
@Deprecated public static SemanticProgram buildDelete(TDeleteSqlStatement delete, NameBindingProvider provider)
public static SemanticBuildResult buildMergeResult(TMergeSqlStatement merge, NameBindingProvider provider, SemanticIRBuildOptions options)
options; see
build(TSelectSqlStatement, NameBindingProvider, SemanticIRBuildOptions).public static SemanticBuildResult buildMergeResult(TMergeSqlStatement merge, NameBindingProvider provider)
@Deprecated public static SemanticProgram buildMerge(TMergeSqlStatement merge, NameBindingProvider provider, SemanticIRBuildOptions options)
@Deprecated public static SemanticProgram buildMerge(TMergeSqlStatement merge, NameBindingProvider provider)