Class ExpressionEvaluator

java.lang.Object
dev.frostlake.executor.ExpressionEvaluator

public class ExpressionEvaluator extends Object
Evaluates expressions against rows.

Expressions are parsed once into an Expression AST (via the ANTLR grammar and ExpressionAstBuilder) and evaluated by ExpressionEvaluatorVisitor. Parse once with parse(String) and call evaluate(Expression, Row) per row to avoid re-parsing.

  • Constructor Details

  • Method Details

    • setQueryExecutor

      public void setQueryExecutor(QueryExecutor queryExecutor)
    • setOuterLateralContext

      public void setOuterLateralContext(Map<String,Object> context)
    • setScopeOpaqueToSubqueries

      public void setScopeOpaqueToSubqueries(boolean opaque)
      Declares this evaluator's relation a PROJECTION SCOPE — a FROM-less select's own item list — which answers the clauses of that select and nothing nested inside them, so a subquery written in one of those clauses does not correlate to it.
      Parameters:
      opaque - whether the relation is such a scope
    • setMultiTableContext

      public void setMultiTableContext(Map<String,Table> aliasToTable, List<Table> allTables)
      Provide a multi-table (JOIN) resolution context so a parsed Expression can be evaluated directly over joined rows with alias-aware column resolution. Set once per query.
    • setResultContext

      public void setResultContext(Map<String,Object> resultContext)
      Provide precomputed SELECT-list outputs (HAVING / QUALIFY), keyed by canonical AST form and alias, so a condition referencing an aggregate/window/alias resolves to the computed value.
    • setDeclaredTypeBase

      public void setDeclaredTypeBase(Table base, Map<String,Table> aliasToTable, List<Table> allTables)
      Parameters:
      base - the base relation, or null
      aliasToTable - its alias map, or null
      allTables - its joined relations, or null
    • evaluate

      public Object evaluate(Expression expression, Row row)
      Evaluate an expression AST against a row (RECOMMENDED) This method is more efficient than string-based evaluation because the expression is already parsed. Use this when you need to evaluate the same expression multiple times.
      Parameters:
      expression - The parsed expression AST
      row - The row to evaluate against
      Returns:
      The result of the expression evaluation
    • evaluate

      public Object evaluate(String expression, Row row)
      Evaluate a string expression against a row: parse it to an AST (cached) and evaluate via ExpressionEvaluatorVisitor. For repeated evaluation of the same text, prefer parse(String) once + evaluate(Expression, Row) per row.
      Parameters:
      expression - the expression as a string
      row - the row to evaluate against
      Returns:
      the result of the expression evaluation
    • validateStrict

      public void validateStrict(Expression expression)
      Plan-time strict-argument validation over a parsed expression: runs the Snowflake argument-type checks for every function call in expression WITHOUT evaluating it, so rejection fires even over zero input rows.
    • validateUdfArguments

      public void validateUdfArguments(Expression expression)
      The plan-time user-defined function argument check alone, over a parsed expression.
    • validateColumnScope

      public void validateColumnScope(Expression expression)
      PHASE ONE of the plan-time walk: every column reference, and nothing else. Live orders its refusals by KIND rather than by position — an invalid identifier beats an unknown function name, which beats every argument-type complaint, whichever item each of them sits in — so the select list is walked once per kind.
    • withNarrowingCastEqualitiesAnswered

      public Expression withNarrowingCastEqualitiesAnswered(Expression predicate)
      A filter's predicate with the narrowing casts live answers without converting dropped: see ExpressionEvaluatorVisitor.withNarrowingCastEqualitiesAnswered(dev.frostlake.executor.expressions.Expression).
      Parameters:
      predicate - the parsed predicate of a WHERE or an ON
      Returns:
      the predicate to evaluate
    • validateFunctionNames

      public void validateFunctionNames(Expression expression)
      PHASE TWO: every call's NAME, and nothing else. See validateColumnScope(dev.frostlake.executor.expressions.Expression).
    • resolvesToAFunctionName

      public boolean resolvesToAFunctionName(Expression expression)
      PHASE TWO as a QUESTION rather than a refusal. validateFunctionNames(dev.frostlake.executor.expressions.Expression) stops at the first unresolvable name, which is right for one expression; a whole statement's refusal names every one of them at once, so the caller asks this per call and refuses after.
      Parameters:
      expression - one parsed call — anything that is not a call answers true
      Returns:
      whether the name resolves
    • unknownFunctionSentence

      public String unknownFunctionSentence(List<FunctionCallExpression> calls)
      Live's sentence for a set of unresolvable calls — see the visitor's own documentation.
    • keyCollation

      public CollationSpec keyCollation(Expression expression)
      The collation an ORDER BY, GROUP BY, DISTINCT, PARTITION BY or set-operation key compares under. A key with none compares by code point, as it always did.
      Parameters:
      expression - the key expression
      Returns:
      its collation rules, or null when it carries none
    • setScopeExemptNames

      public void setScopeExemptNames(Set<String> names)
      Bare names the plan-time scope walk must not reject — the query's SELECT output aliases / output column names, legal in every non-SELECT clause (WHERE included, live-verified).
    • setOutputScopeNames

      public void setOutputScopeNames(Set<String> names)
      The names a refusal's echo prints BARE, because the expression it re-prints resolves in the query's OUTPUT scope rather than against the FROM — a projected column has no relation to name.
      Parameters:
      names - the output column names, upper-cased
    • setOutputAliasTypes

      public void setOutputAliasTypes(Map<String,DataType> types)
      The static types of the query's SELECT output aliases, so a bare alias in a predicate is typed from the expression it names.
      Parameters:
      types - alias name (upper-cased) to type
    • validateStrictWindowed

      public void validateStrictWindowed(Expression expression)
      validateStrict(dev.frostlake.executor.expressions.Expression) for a WINDOW call re-formed without its OVER clause — the walk runs with the windowed marker set, so the bare-form desugared-name rewrites stay off (live reports the WRITTEN name for windowed forms, measured).
    • validateKey

      public void validateKey(Expression expression, SortKeyRole role)
      Key-position validation: Snowflake rejects a FILE-typed expression used as a GROUP BY, ORDER BY or window PARTITION BY key at compile time, while leaving it usable everywhere else (equality, DISTINCT, joins). Run once per query on each parsed key, before any row is compared.
    • validateOrderedValue

      public void validateOrderedValue(Expression expression)
      WITHIN GROUP (ORDER BY …) value validation: Snowflake rejects a semi-structured value in the position an ordering aggregate accumulates, with the same "incompatible types" sentence MEDIAN uses for its argument. Run once per query on the parsed clause expression.
    • validateCollations

      public void validateCollations(Expression expression)
      A JOIN condition's collation rules, judged before any row is read — see ExpressionEvaluatorVisitor.validateCollations(dev.frostlake.executor.expressions.Expression).
      Parameters:
      expression - the parsed ON condition
    • collationOf

      public String collationOf(Expression expression)
      The collation expression carries, lower-cased, or null for none — see ExpressionEvaluatorVisitor.collationOf(dev.frostlake.executor.expressions.Expression). Over no relation a column reference carries none, so what is left is what the expression names itself.
      Parameters:
      expression - the parsed expression
      Returns:
      its collation specification, or null
    • validatePredicate

      public void validatePredicate(Expression expression)
      Predicate-position validation (Snowflake rejects VARCHAR/NUMBER-typed WHERE, HAVING and QUALIFY conditions at compile time) — run once per query on the parsed predicate before row evaluation. The BOOLEAN positions INSIDE the predicate — a searched CASE's WHEN, IFF's condition — are judged first, by the same narrow walk, so a CASE over a VARCHAR refuses here as it does in a SELECT list.

      The GEOSPATIAL comparison walk runs here too. It is a separate, deliberately NARROW walk rather than the full validateStrict(dev.frostlake.executor.expressions.Expression) one: a WHERE clause is where a geo comparison is actually written (WHERE g = TO_GEOGRAPHY(…), JOIN … ON a.g = b.g lowered into a filter), live refuses every such spelling, and a rule that can only fire on a statically GEOGRAPHY- or GEOMETRY-typed operand cannot reject anything else. Running the whole strict walk here would newly enforce the OBJECT / FILE operator rules in predicate position as well, which has not been measured and is not this rule's business.

    • validateBooleanPositions

      public void validateBooleanPositions(Expression expression)
      The BOOLEAN positions inside expression — a searched CASE's WHEN conditions, IFF's condition — judged at plan time on their static types, for a path that evaluates values before the strict walk would type them (the FROM-less select list).
      Parameters:
      expression - the parsed expression
    • inferStaticType

      public DataType inferStaticType(Expression expression)
      The type expression is statically KNOWN to produce in this table context, or null when it cannot be determined. Used at projection time to give a derived relation (subquery, CTE, view) a typed column list, so an outer reference to one of its columns resolves to the inner expression's type instead of the VARCHAR placeholder. Never throws: an expression this evaluator cannot even look at is simply undetermined.
    • countsStoredColumn

      public boolean countsStoredColumn(Expression argument)
      Whether a COUNT over argument is answered from the statistics: over a constant or a stored column (see ExpressionEvaluatorVisitor#countsStoredColumn).
      Parameters:
      argument - the COUNT's one argument
      Returns:
      true when the statistics answer it
    • spelledNumber

      public DataType spelledNumber(Expression expression)
      The NUMBER expression spells when it is a bare string literal, or a column carrying one out of a derived relation — what a projected column hands on so a conditional over it folds as live folds the literal (see TableColumn#getSpelledNumber); null for anything else. Never throws.
    • inferStaticRange

      public ValueRange inferStaticRange(Expression expression)
      The interval expression's values lie in, as the account's statistics would bound it, or null when none can be known. The channel that decides SYSTEM$TYPEOF's storage tag; never throws.
    • rejectArgumentFamilies

      public void rejectArgumentFamilies(Expression expression)
      Applies the argument-family refusals to every call in expression from declared types, before any row is read — see ExpressionEvaluatorVisitor.rejectArgumentFamilies(dev.frostlake.executor.expressions.Expression).
    • argumentTypeText

      public String argumentTypeText(Expression expression)
      How Snowflake NAMES an expression's type when it refuses it as an argument — VARCHAR(7) for a seven-character literal, VARCHAR(50) for a declared column, NUMBER(1,0), DATE. A literal is measured from its own text, so the width is the value's, not the family's maximum.
    • qualifiedText

      public String qualifiedText(Expression expression)
      How Snowflake RE-PRINTS an expression when it names it in a refusal: from the analysed plan, so a bare column reference comes back qualified with the name its relation is known by in scope — n over FROM eb prints EB.N, and over FROM eb x prints X.N. Keyword and identifier case and all spacing are normalised with it.
    • qualifiedAggregateText

      public String qualifiedAggregateText(Expression expression)
      qualifiedText(dev.frostlake.executor.expressions.Expression) for an aggregate call that a NESTING message brackets: a plain AVG at that root prints as its SUM half, the way live names it — see ExpressionEvaluatorVisitor.strictAggregateText(dev.frostlake.executor.expressions.Expression).
    • parse

      public static Expression parse(String expression)
      Parse an expression string into an Expression AST — the parse-once entry point for operators that previously re-evaluated the same text once per row. Parses via the ANTLR grammar and caches by text. Blank input yields a literal TRUE (matching the old empty-predicate behaviour).

      -- line comments are handled by the ANTLR lexer (LINE_COMMENT -> skip), which tokenizes string literals first — so a literal such as 'a--b' keeps its dashes. (A prior quote-blind regex pre-strip here truncated any literal containing --.)