Interface OptimizationRule
- All Known Implementing Classes:
PassRule
Each rule encapsulates one rewrite family (identified by its code(),
or by codes() for a rule that emits several related codes) and is applied
to a RelNode tree by QueryOptimizer. The rules that make up the
default pipeline, the order they run in, and which of them are iterated to a
fixpoint are declared by OptimizationPipeline. Rules must be:
- Idempotent — applying the same rule twice to an already-optimized tree returns the same result as applying it once.
- Semantics-preserving — the rewritten tree must produce identical results to the original for any legal input.
- Stateless (recommended) — implementations should carry no mutable state so they are safe to share across multiple optimization runs.
Contract for apply(com.darkcollective.relix.ast.RelNode, java.lang.String, com.darkcollective.relix.semantic.SchemaAnnotations, com.darkcollective.relix.optimizer.internal.OptimizationContext)
- Return the original
nodeunchanged when the rule does not apply to this node. Do not callOptimizationContext.record(com.darkcollective.relix.optimizer.OptimizationCode, java.lang.String, java.lang.String, com.darkcollective.relix.ast.SourceLocation)in this case. - Return a rewritten
RelNodewhen the rule fires, and callctx.record()exactly once per top-level rewrite performed at this node. - Most rules only inspect the current node and rely on the
QueryOptimizerengine to handle bottom-up or top-down traversal. Rules that need to recurse into children explicitly should document this clearly.
The two obligations above are what OptimizationPipeline's
fixpoint driver reads as "progress". It re-runs an iterated phase only
while its rules both recorded something and returned a different tree
(reference inequality, per RelNode.mapChildren(java.util.function.UnaryOperator<com.darkcollective.relix.ast.RelNode>)'s identity contract). A
rule that rewrites without recording, or records without rewriting, is not a
correctness bug on its own but does stop the phase early.
-
Method Summary
Modifier and TypeMethodDescriptionapply(RelNode node, String queryName, SchemaAnnotations schemas, OptimizationContext ctx) Applies this rule to the given node, returning either the original node (if the rule did not fire) or a rewritten node (if it did).code()Returns theOptimizationCodethat identifies this rule.default List<OptimizationCode> codes()Returns everyOptimizationCodethis rule can emit, primary first.default Stringname()Returns a short stable identifier for this rule, used when a pipeline is rendered or a rule is named in a diagnostic.
-
Method Details
-
code
OptimizationCode code()Returns theOptimizationCodethat identifies this rule.For a rule that emits several codes this is the primary one — the first entry of
codes().- Returns:
- the code; never null
-
codes
Returns everyOptimizationCodethis rule can emit, primary first.Rules are registered one per pass, and several passes cover a family of related rewrites —
SelectionPushdownPassalone emitsSEL-003..009. The default implementation returns justcode(), which is right for a single-code rule.- Returns:
- unmodifiable list, never null or empty
-
name
Returns a short stable identifier for this rule, used when a pipeline is rendered or a rule is named in a diagnostic.Defaults to the primary
code()'s code string.- Returns:
- the name; never null or blank
-
apply
Applies this rule to the given node, returning either the original node (if the rule did not fire) or a rewritten node (if it did).- Parameters:
node- the node to inspect and possibly rewrite; never nullqueryName- display name of the relation/query being optimized, used inTransformationRecords; never blankschemas- schema annotations from semantic analysis; rules that need to know a node's output schema use this to look it up; never nullctx- mutable context that accumulates transformation records; never null- Returns:
- the original
nodewhen the rule did not fire, or a newRelNoderepresenting the rewritten tree; never null
-