Skip to content

Commit fd1de1d

Browse files
committed
fix: drop JSONExtract chains iteratively
The Databricks parser builds a v:a:a:… path in a loop, one JSONExtract per link, each holding the previous one as its input. JSONExtract was missing from the iterative drop list, so freeing a long path recursed once per link: on a 2 MiB thread, SELECT v:a:a:… FROM t aborted with a stack overflow from about 20,000 links in debug and 50,000 in release, including after the parser had refused the tree for depth. JSONExtract now frees its descendants with the worklist, like JsonExtractFunc and the other loop-built nodes, and the 100,000-step drop test covers it.
1 parent a9dde6a commit fd1de1d

2 files changed

Lines changed: 22 additions & 1 deletion

File tree

‎crates/sqlquack-syntax/src/expressions/tree/_helpers/drops.rs‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
//! Iterative drops for nodes a parser chains in a loop, such as `x::INT::INT`, `v[1][1]` or `q |> WHERE a |> WHERE b`.
1+
//! Iterative drops for nodes a parser chains in a loop, such as `x::INT::INT`, `v[1][1]`, `v:a:a` or `q |> WHERE a |> WHERE b`.
22
33
use crate::expressions::functions::models::JSONCast;
4+
use crate::expressions::functions::models::JSONExtract;
45
use crate::expressions::functions::models::Operator;
56
use crate::expressions::functions::models::Xor;
67
use crate::expressions::operators::models::Alias;
@@ -62,6 +63,7 @@ drop_iteratively!(
6263
IsNull,
6364
IsTrueFalse,
6465
JSONCast,
66+
JSONExtract,
6567
JsonExtractFunc,
6668
LikeOp,
6769
MatchRecognize,

‎crates/sqlquack-syntax/src/guard/tests/test_ast_guard.rs‎

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use crate::expressions::functions::models::JSONCast;
2+
use crate::expressions::functions::models::JSONExtract;
23
use crate::expressions::functions::models::Operator;
34
use crate::expressions::functions::models::Xor;
45
use crate::expressions::names::models::Identifier;
@@ -424,6 +425,24 @@ fn given_a_100_000_step_chain_of_a_node_parsers_build_in_a_loop_when_dropping_on
424425
},
425426
expected_depth: 100_000,
426427
},
428+
ChainStepTestCase {
429+
description: "Databricks v:a:a paths",
430+
step: |input| {
431+
Expression::JSONExtract(Box::new(JSONExtract {
432+
this: Box::new(input),
433+
expression: Box::new(Expression::number(1)),
434+
only_json_types: None,
435+
expressions: Vec::new(),
436+
variant_extract: None,
437+
json_query: None,
438+
option: None,
439+
quote: None,
440+
on_condition: None,
441+
requires_json: None,
442+
}))
443+
},
444+
expected_depth: 100_000,
445+
},
427446
ChainStepTestCase {
428447
description: "array slices",
429448
step: |input| {

0 commit comments

Comments
 (0)