java.lang.Object
java.lang.Record
com.darkcollective.relix.processor.internal.ExecutionContext
Record Components:
symbolTable - the fully-populated symbol table; must not be null
nodeSchemas - per-node schema annotations from inference; must not be null
statistics - per-relation statistics for the planner's cost model; must not be null
sources - canonical name → source declaration, for SQL pushdown planning; must not be null
connections - canonical name → connection declaration, for SQL pushdown planning; must not be null
connector - the data-source connector for external relations; must not be null
listener - observer notified of execution-stage QueryEvents (e.g. a declarative-optimisation group skipped as infeasible); QueryEventListener.NONE to ignore them; must not be null
maxFixpointRounds - maximum number of semi-naïve fixpoint iterations before aborting with an EvaluationException; use UNLIMITED_FIXPOINT_ROUNDS for no cap (the default); must be ≥ 1
maxMaterializedRows - maximum rows a single blocking operator (γ, τ, a deduplicating set operation, a hash join's build side, …) may buffer before aborting with an EvaluationException naming it. Bounds one operator rather than a run's total, exactly as maxFixpointRounds bounds one fixpoint; use UNLIMITED_MATERIALIZED_ROWS for no cap (the default); must be ≥ 1
maxProcessedRows - maximum rows one execution's operators may pass to one another in total before aborting with an EvaluationException: a deterministic measure of work, which stops a query that runs long while producing little. Use UNLIMITED_PROCESSED_ROWS for no cap (the default); must be ≥ 1
timeout - how long one execution may run before aborting with an EvaluationException, checked as rows pass between operators; use UNLIMITED_TIMEOUT for none (the default); must be positive
clock - the clock the current-time built-ins (NOW, CURRENT_DATE, CURRENT_TIME) read. Read once, when the context is made: what the context keeps is that instant, so every row of every query run through it sees the same moment. Supplying a pinned clock (see withClock(java.time.Clock)) additionally makes the run reproducible — the same script over the same data yields the same rows however much later it is replayed. Clock.systemUTC() by default; must not be null
functions - the function catalogue every call is evaluated against — the same one the model was analysed against, so analysis and evaluation cannot disagree about what a name means. of(SemanticModel, DataSourceConnector) takes it from the model; a context built without one gets installedFunctions(). Must not be null

public record ExecutionContext(SymbolTable symbolTable, SchemaAnnotations nodeSchemas, Map<String,RelationStatistics> statistics, Map<String,SourceDeclaration> sources, Map<String,ConnectionDeclaration> connections, DataSourceConnector connector, QueryEventListener listener, int maxFixpointRounds, int maxMaterializedRows, long maxProcessedRows, Duration timeout, Clock clock, FunctionCatalog functions) extends Record
Shared execution state threaded through all operators during query evaluation.

An ExecutionContext bundles the three things an operator may need at runtime:

  • symbolTable() — used by RelationExecutor to resolve a relation name to its symbol (inline rows, query body, or external source).
  • nodeSchemas() — the per-node schema annotations produced by semantic analysis; used to construct Row objects with the correct column set when opening a source.
  • connector() — called only for DatabaseRelationSymbol and SourceRelationSymbol relations that require external I/O. Inline relations are served directly from the symbol table without calling the connector.

Construction

Prefer the factory methods over the canonical record constructor:

Precondition

The executor assumes it receives a fully valid SemanticModel. Passing an unvalidated model (e.g. result.isFullyValid() == false) may cause EvaluationExceptions that should have been caught during semantic analysis.

  • Field Details

    • UNLIMITED_FIXPOINT_ROUNDS

      public static final int UNLIMITED_FIXPOINT_ROUNDS
      Sentinel value meaning no cap on fixpoint iteration rounds; also the default.
      See Also:
    • UNLIMITED_MATERIALIZED_ROWS

      public static final int UNLIMITED_MATERIALIZED_ROWS
      Sentinel value meaning no cap on a blocking operator's buffer.
      See Also:
    • DEFAULT_MAX_MATERIALIZED_ROWS

      public static final int DEFAULT_MAX_MATERIALIZED_ROWS
      The buffer a blocking operator is allowed by default — ten million rows.

      A cap and a sentinel are not the same decision. Passing UNLIMITED_MATERIALIZED_ROWS still means no cap; this is what a context that names no number gets, and until now that was the sentinel.

      The number is chosen to be one no reasonable query reaches and every runaway does. What it buys is not memory — ten million rows is a great deal of memory — but attribution: past it the query fails naming the operator that buffered and the knob that raises the limit, where before the host JVM died with an OutOfMemoryError belonging to nobody. This engine runs inside someone else's process, so that error takes their program down and tells them nothing.

      The fixpoint round count is deliberately not given the same treatment. How many rounds a legitimate recursion needs is a property of the data — a transitive closure over a long chain needs one round per hop — so any default there refuses some correct query, and a truncated answer is harder to diagnose than a hang. UNLIMITED_FIXPOINT_ROUNDS remains the default and stays opt-in.

      See Also:
    • UNLIMITED_PROCESSED_ROWS

      public static final long UNLIMITED_PROCESSED_ROWS
      No cap on the rows one execution's operators may process, which is the default.
      See Also:
    • UNLIMITED_TIMEOUT

      public static final Duration UNLIMITED_TIMEOUT
      No timeout on one execution, which is the default.
  • Constructor Details

    • ExecutionContext

      public ExecutionContext(SymbolTable symbolTable, SchemaAnnotations nodeSchemas, Map<String,RelationStatistics> statistics, Map<String,SourceDeclaration> sources, Map<String,ConnectionDeclaration> connections, DataSourceConnector connector, QueryEventListener listener, int maxFixpointRounds, int maxMaterializedRows, long maxProcessedRows, Duration timeout, Clock clock, FunctionCatalog functions)
      Creates an instance of a ExecutionContext record class.
      Parameters:
      symbolTable - the value for the symbolTable record component
      nodeSchemas - the value for the nodeSchemas record component
      statistics - the value for the statistics record component
      sources - the value for the sources record component
      connections - the value for the connections record component
      connector - the value for the connector record component
      listener - the value for the listener record component
      maxFixpointRounds - the value for the maxFixpointRounds record component
      maxMaterializedRows - the value for the maxMaterializedRows record component
      maxProcessedRows - the value for the maxProcessedRows record component
      timeout - the value for the timeout record component
      clock - the value for the clock record component
      functions - the value for the functions record component
    • ExecutionContext

      public ExecutionContext(SymbolTable symbolTable, SchemaAnnotations nodeSchemas, Map<String,RelationStatistics> statistics, Map<String,SourceDeclaration> sources, Map<String,ConnectionDeclaration> connections, DataSourceConnector connector)
      Convenience constructor that observes no execution events (QueryEventListener.NONE) and imposes no fixpoint cap. Keeps the common construction path — and every existing call site — free of those parameters.
      Parameters:
      symbolTable - the fully-populated symbol table; must not be null
      nodeSchemas - per-node schema annotations; must not be null
      statistics - per-relation statistics; must not be null
      sources - canonical name → source declaration; must not be null
      connections - canonical name → connection declaration; must not be null
      connector - the data-source connector; must not be null
    • ExecutionContext

      public ExecutionContext(SymbolTable symbolTable, SchemaAnnotations nodeSchemas, DataSourceConnector connector)
      Convenience constructor for contexts with no statistics and no pushdown metadata (the planner uses tier-based cost only and never pushes SQL).
      Parameters:
      symbolTable - the fully-populated symbol table; must not be null
      nodeSchemas - per-node schema annotations; must not be null
      connector - the data-source connector; must not be null
  • Method Details

    • functionContext

      public FunctionContext functionContext()
      The ambient state a function implementation may read while it runs — today the clock, so a pinned run is reproducible down to NOW().

      It also carries the engine's total order over values, which is what an aggregate that ranks its input — MIN, ARGMAX — reduces by.

      Build it once per execution and hold it: it is a field of the evaluator, not something to make per call.

      Returns:
      the function context for this execution
    • installedFunctions

      public static FunctionCatalog installedFunctions()
      The catalogue over whichever function libraries are installed, discovered once.

      Discovery scans the module path, so doing it per context — let alone per query — would be paid for on every run. It is also the answer that must not vary: two catalogues assembled separately can disagree about what a name means. A context built from a SemanticModel uses that model's catalogue instead, which is the same one analysis resolved against.

      Returns:
      the catalogue of installed function libraries
    • boundedness

      public BoundednessSource boundedness()
      The per-leaf BoundednessSource for this context — a generator source reports its declared boundedness, every other leaf is bounded. Used by the planner's materialisation-safety check and join build-side rule. Derived from sources(), so it needs no extra construction or threading.
      Returns:
      the boundedness source for the relations in this context
    • withListener

      public ExecutionContext withListener(QueryEventListener listener)
      Returns a copy of this context that emits execution-stage events to listener. All other fields are shared unchanged.
      Parameters:
      listener - the observer to attach; must not be null
      Returns:
      a new context with the given listener
    • withMaxFixpointRounds

      public ExecutionContext withMaxFixpointRounds(int maxFixpointRounds)
      Returns a copy of this context with the given fixpoint-iteration cap. All other fields are shared unchanged.
      Parameters:
      maxFixpointRounds - the maximum number of semi-naïve fixpoint iterations allowed before an EvaluationException is thrown; must be ≥ 1; use UNLIMITED_FIXPOINT_ROUNDS for no cap
      Returns:
      a new context with the given limit
    • withMaxMaterializedRows

      public ExecutionContext withMaxMaterializedRows(int maxMaterializedRows)
      Returns a copy of this context with the given cap on how many rows one blocking operator may buffer. All other fields are shared unchanged.

      The guard for the failure a plan cannot see. BoundednessChecker refuses a blocking operator over an unbounded input, and a collecting terminal refuses to gather one; neither says anything about size, so a bounded table far larger than the heap plans happily and dies with an OutOfMemoryError attributable to no operator in particular. Under a cap the same query stops with an EvaluationException naming the operator that was buffering.

      It bounds one operator's buffer rather than a run's total — the shape withMaxFixpointRounds(int) has, which likewise bounds one fixpoint. A running total would refuse a fixpoint that buffers the same thousand rows each round without its peak memory ever moving.

      Parameters:
      maxMaterializedRows - the maximum rows a single blocking operator may buffer; must be ≥ 1; use UNLIMITED_MATERIALIZED_ROWS for no cap
      Returns:
      a new context with the given limit
    • withMaxProcessedRows

      public ExecutionContext withMaxProcessedRows(long maxProcessedRows)
      Returns a copy of this context with the given cap on the rows one execution may process. All other fields are shared unchanged.

      A row is counted each time an operator hands one to the operator above it, so the count is the sum of every operator's output. That is what stops the two queries a cap on output cannot: a selection over an endless generator that matches nothing, and an aggregate over a large product that emits a single row. It is a running total for the whole execution, recursion included, because what it bounds is work done rather than memory held.

      Parameters:
      maxProcessedRows - the maximum rows processed; must be ≥ 1; use UNLIMITED_PROCESSED_ROWS for no cap
      Returns:
      a new context with the given limit
    • withTimeout

      public ExecutionContext withTimeout(Duration timeout)
      Returns a copy of this context with the given limit on how long one execution may run. All other fields are shared unchanged.

      The clock starts when execution does, not when planning does. It is checked as rows pass between operators, so it cannot interrupt a call that does not return to the engine: a JDBC driver waiting on its database, or a solver's search.

      Parameters:
      timeout - the longest one execution may run; must be positive; use UNLIMITED_TIMEOUT for none
      Returns:
      a new context with the given limit
    • withClock

      public ExecutionContext withClock(Clock clock)
      Returns a copy of this context whose current-time built-ins read clock. All other fields are shared unchanged.

      This is the reproducibility seam: pin the clock and NOW(), CURRENT_DATE() and CURRENT_TIME() become fixed for the whole run, so a script with a relative time window (NOW() - DURATION 'PT1H') selects the same rows today and next month. The CLI exposes it as --now / RELIX_NOW.

      The functions stay non-PURE and non-DETERMINISTIC in the registry regardless: under the default clock they still advance, so the optimizer must never fold or dedupe them.

      Parameters:
      clock - the clock to read; must not be null
      Returns:
      a new context reading the given clock
    • withFunctions

      public ExecutionContext withFunctions(FunctionCatalog functions)
      Returns a copy of this context whose function calls are evaluated against functions. All other fields are shared unchanged.

      The catalogue normally arrives from the analysed model, which is what keeps analysis and evaluation agreeing about what a name means. Overriding it is for a caller that assembled its own — an embedder installing a library programmatically rather than through discovery.

      Parameters:
      functions - the catalogue to evaluate calls against; must not be null
      Returns:
      a new context over the given catalogue
    • of

      public static ExecutionContext of(SemanticModel model, DataSourceConnector connector)
      Creates an ExecutionContext from a validated SemanticModel and a DataSourceConnector for external relations. Pulls statistics, sources, and connections from the model so cost-based planning and SQL pushdown are enabled.
      Parameters:
      model - the fully-validated semantic model; must not be null
      connector - the connector supplying external rows; must not be null
      Returns:
      a new context
    • of

      public static ExecutionContext of(SemanticModel model, SchemaAnnotations nodeSchemas, DataSourceConnector connector)
      Creates an ExecutionContext from a model and connector but with an overriding set of schema annotations — used when executing an optimizer-rewritten tree whose nodes are absent from SemanticModel.nodeSchemas().
      Parameters:
      model - the semantic model; must not be null
      nodeSchemas - the annotations covering the tree to execute; must not be null
      connector - the connector supplying external rows; must not be null
      Returns:
      a new context
    • inlineOnly

      public static ExecutionContext inlineOnly(SemanticModel model)
      Creates an ExecutionContext for scripts that contain only inline relations. Any attempt to open an external data source via the connector throws EvaluationException.
      Parameters:
      model - the fully-validated semantic model; must not be null
      Returns:
      a new context whose connector rejects all external source requests
    • toString

      public final String toString()
      Returns a string representation of this record class. The representation contains the name of the class, followed by the name and value of each of the record components.
      Specified by:
      toString in class Record
      Returns:
      a string representation of this object
    • hashCode

      public final int hashCode()
      Returns a hash code value for this object. The value is derived from the hash code of each of the record components.
      Specified by:
      hashCode in class Record
      Returns:
      a hash code value for this object
    • equals

      public final boolean equals(Object o)
      Indicates whether some other object is "equal to" this one. The objects are equal if the other object is of the same class and if all the record components are equal. Reference components are compared with Objects::equals(Object,Object); primitive components are compared with '=='.
      Specified by:
      equals in class Record
      Parameters:
      o - the object with which to compare
      Returns:
      true if this object is the same as the o argument; false otherwise.
    • symbolTable

      public SymbolTable symbolTable()
      Returns the value of the symbolTable record component.
      Returns:
      the value of the symbolTable record component
    • nodeSchemas

      public SchemaAnnotations nodeSchemas()
      Returns the value of the nodeSchemas record component.
      Returns:
      the value of the nodeSchemas record component
    • statistics

      public Map<String,RelationStatistics> statistics()
      Returns the value of the statistics record component.
      Returns:
      the value of the statistics record component
    • sources

      public Map<String,SourceDeclaration> sources()
      Returns the value of the sources record component.
      Returns:
      the value of the sources record component
    • connections

      public Map<String,ConnectionDeclaration> connections()
      Returns the value of the connections record component.
      Returns:
      the value of the connections record component
    • connector

      public DataSourceConnector connector()
      Returns the value of the connector record component.
      Returns:
      the value of the connector record component
    • listener

      public QueryEventListener listener()
      Returns the value of the listener record component.
      Returns:
      the value of the listener record component
    • maxFixpointRounds

      public int maxFixpointRounds()
      Returns the value of the maxFixpointRounds record component.
      Returns:
      the value of the maxFixpointRounds record component
    • maxMaterializedRows

      public int maxMaterializedRows()
      Returns the value of the maxMaterializedRows record component.
      Returns:
      the value of the maxMaterializedRows record component
    • maxProcessedRows

      public long maxProcessedRows()
      Returns the value of the maxProcessedRows record component.
      Returns:
      the value of the maxProcessedRows record component
    • timeout

      public Duration timeout()
      Returns the value of the timeout record component.
      Returns:
      the value of the timeout record component
    • clock

      public Clock clock()
      Returns the value of the clock record component.
      Returns:
      the value of the clock record component
    • functions

      public FunctionCatalog functions()
      Returns the value of the functions record component.
      Returns:
      the value of the functions record component