Apply AST size limits to the query generated by table function eval - #110211
Apply AST size limits to the query generated by table function eval#110211groeneai wants to merge 9 commits into
Conversation
The eval table function parses and stores the generated inner SELECT but,
unlike executeQueryImpl, never applied the AST size limits. That made
max_ast_depth and max_ast_elements ineffective for the inner query: a tiny
outer SELECT * FROM eval('...') could smuggle a huge or very deep AST into
the analyzer, even though executing the same inner query directly would be
rejected.
Apply checkDepth/checkSize to the generated query, reading the limits from a
context that already has the generated query's own SETTINGS applied (resolved
before the normalization visitors rewrite the tree), so an inner SETTINGS
clause controls its own limits the same way it does for a standalone query.
Follow-up to ClickHouse#110132.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Pre-PR validation gate (click to expand)
Session id: cron:clickhouse-worker-slot-0:20260713-042100 |
|
cc @alexey-milovidov — follow-up to #110132 as requested: applies the AST size limits to the query generated by |
|
Workflow [PR], commit [2ad4949] Summary: ❌
|
The generated query's INTERSECT/EXCEPT and UNION normalization ran with the outer context defaults, so an inner SETTINGS union_default_mode = 'DISTINCT' still threw EXPECTED_ALL_OR_DISTINCT even though the same query executes fine directly. Drive the normalization visitors from limits_context (the inner query's resolved SETTINGS), same as the AST size limits already do. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Fixed in f502546. The set-operation normalization visitors now read Verified both directions with your repro on a debug build:
Added a regression in Pre-PR validation gate (click to expand)
Session id: cron:clickhouse-worker-slot-2:20260713-083200 |
Mirror executeQueryImpl ordering: run ApplyWithGlobalVisitor (gated by the inner query's enable_global_with_statement) before the AST size checks, so a global CTE that stays small before expansion but grows past max_ast_elements once inlined into every UNION branch is rejected in eval like in a direct query. Add a regression to 04512_eval_table_function. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Fixed in efef3e9. Pre-PR validation gate (click to expand)
Session id: cron:clickhouse-worker-slot-1:20260713-093100 |
| -- non-deterministic and potentially reading a system table, and is not cached by default. | ||
| SELECT * FROM eval('SELECT now()') SETTINGS use_query_cache = 1; -- { serverError QUERY_CACHE_USED_WITH_NONDETERMINISTIC_FUNCTIONS } | ||
| SELECT * FROM eval('SELECT * FROM system.one') SETTINGS use_query_cache = 1, query_cache_nondeterministic_function_handling = 'save'; -- { serverError QUERY_CACHE_USED_WITH_SYSTEM_TABLE } | ||
|
|
There was a problem hiding this comment.
Could you add a new test instead of modifying existing one?
There was a problem hiding this comment.
Done in a755995. Moved the new regressions into a dedicated 04513_eval_table_function_ast_limits.sql; 04512_eval_table_function.sql/.reference are restored to their pre-PR content.
Pre-PR validation gate (click to expand)
| # | Check | Result |
|---|---|---|
| a | Deterministic repro? | N/A (test-file reorganization, no code change) |
| b | Root cause explained? | N/A |
| c | Fix matches root cause? | N/A |
| d | Test intent preserved / new tests added? | Yes: the seven assertions are byte-identical, only relocated; 04512 is back to its pre-PR state |
| e | Demonstrated both directions? | Yes: all 7 assertions verified against the fixed binary (inner DISTINCT -> 1, ambiguous UNION -> EXPECTED_ALL_OR_DISTINCT, outer/inner max_ast_elements -> TOO_BIG_AST, max_ast_depth -> TOO_DEEP_AST, inner relax -> 55, global-WITH expansion -> TOO_BIG_AST) |
| f | Fix general, not a narrow patch? | N/A (no code bug) |
| g | Generalizes across inputs/types? | N/A |
| h | Backward compatible? | N/A |
| i | Invariants/contracts preserved? | Yes: new test is parallel-safe (no shared state, no no-parallel) |
Session id: cron:clickhouse-worker-slot-1:20260713-113700
Move the union_default_mode / max_ast_* / global-WITH regressions added by this PR out of 04512_eval_table_function into a new 04513 test, restoring 04512 to its pre-PR content, as requested in review. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
CI finish ledger — a755995Every failure below has an owner: a fixing PR (ours), or the private sync (exempt).
Session id: cron:our-pr-ci-monitor:20260713-183000 |
The intersect_default_mode / except_default_mode branches of SelectIntersectExceptQueryVisitor are driven from the inner query's own settings, but 04513 only exercised UNION. Add a duplicate-sensitive INTERSECT case and an EXCEPT case with inner default mode ALL over an outer DISTINCT, so eval keeps duplicates the same way direct execution does. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
CI finish ledger — d9ed60bEvery failure below has an owner. Only
Session id: cron:our-pr-ci-monitor:20260714-093000 |
LLVM Coverage Report
Changed lines: Changed C/C++ lines covered: 16/16 (100.00%) · Uncovered code |
CI finish ledger — 442563cEvery failure below has an owner: a fixing PR (mine or external), or a full-effort fix task
This is a lane-reachability regression, not a defect in this PR: the test became reachable on the Session id: cron:our-pr-ci-monitor:20260729-060000 |
Changelog category (leave one):
Changelog entry (a user-readable short description of the changes that goes into CHANGELOG.md):
Apply the AST size limits
max_ast_depthandmax_ast_elementsto the query generated by theevaltable function, same as for a query executed directly.Description
Follow-up to #110132 (per @ alexey-milovidov's review request on
src/TableFunctions/TableFunctionEval.cpp).evalparses and stores the generated innerSELECTbut, unlikeexecuteQueryImpl, never applied the AST size limits. That mademax_ast_depth/max_ast_elementsineffective for the inner query: a tiny outerSELECT * FROM eval('...')could smuggle a huge or very deep AST into the analyzer, even though executing the same inner query directly would be rejected.This applies
checkDepth/checkSizeto the generated query, reading the limits from a context that already has the generated query's ownSETTINGSapplied. The settings are resolved before the normalization visitors rewrite the query tree (which can move or drop theSETTINGSclause), so an inner... SETTINGS max_ast_elements = Ncontrols its own limits both to tighten and to relax them, the same way it would for a standalone query.Regression tests added to
04512_eval_table_function.