Skip to content

Consider mapping SQL now()/CURRENT_TIMESTAMP (incl. ClickHouse now()) to EvalTime #184

Description

@milindsrivastava1997

Summary

Verified empirically (see #181/#182/#183 investigation) that ClickHouse SQL now() does not map to QueryExpr::EvalTime today — nothing in frontend-sql recognizes it. It falls into the generic, semantically-opaque catch-all at crates/frontend-sql/src/sql/expr.rs:176:

Expr::ScalarFunction(sf) => Ok(L2Expr::FunctionCall { name: sf.func.name().to_string(), args: args? }),

So WHERE time < NOW() lowers to Scan.predicates: [Compare { .., right: FunctionCall { name: "now", args: [] } }] — correct at runtime (DataFusion still evaluates now() properly), but the IR has no semantic tag that this predicate's truth value is evaluation-time-dependent, the same information EvalTime exists to carry for PromQL's time().

Why this isn't a one-line fix

EvalTime is a relational QueryExpr node (a leaf, like Scan) — that's what lets PromQL embed it directly, since PromQL's IR has no relational/scalar split: time() alone is the whole query (QueryExpr::EvalTime), and time() - 3600 is BinaryOp { lhs: EvalTime, rhs: Scalar(3600.0) } because BinaryOp operands are themselves QueryExpr.

SQL's IR is split: relational QueryExpr (Scan/Filter/Project/...) wraps a separate scalar-expression sub-language (L2Expr/L3Expr) for anything inside a predicate or projection list. NOW() almost never appears as an entire SQL query on its own — it appears embedded in that scalar layer (WHERE time < NOW(), SELECT ts, NOW() - ts AS age FROM ...). You can't drop a QueryExpr node into an L3Expr position; they're different types. So two genuinely different cases:

  1. SELECT NOW() (bare, evaluation time is the whole query) — maps cleanly to top-level QueryExpr::EvalTime, same shape as PromQL's bare time(). (Currently this specific case doesn't even lower today — separately broken on an unrelated EmptyRelation plan-node gap, a FROM-less SELECT.)
  2. NOW() embedded in a predicate/projection (the common case) — has no home in the current L3Expr vocabulary. Making this evaluation-time-aware would need a new L3Expr/L2Expr variant at the scalar layer (e.g. L3Expr::EvalTime), not a match arm added to the relational EvalTime node.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions