Skip to content

Commit f8a4d9b

Browse files
authored
feat(query): better script engine with dynamic schema support (#18838)
* feat: better script engine * update * update * update * fix tests * update call procedure * support cursor * support cursor * support cursor * support cursor * support cursor * update * update
1 parent 33604b6 commit f8a4d9b

File tree

28 files changed

+879
-174
lines changed

28 files changed

+879
-174
lines changed

src/query/ast/src/ast/statements/call.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,11 @@ use derive_visitor::Drive;
1919
use derive_visitor::DriveMut;
2020

2121
use crate::ast::write_comma_separated_string_list;
22+
use crate::ast::Identifier;
2223

2324
#[derive(Debug, Clone, PartialEq, Eq, Drive, DriveMut)]
2425
pub struct CallStmt {
25-
pub name: String,
26+
pub name: Identifier,
2627
pub args: Vec<String>,
2728
}
2829

src/query/ast/src/ast/statements/procedure.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,16 +21,17 @@ use derive_visitor::DriveMut;
2121
use crate::ast::write_comma_separated_list;
2222
use crate::ast::CreateOption;
2323
use crate::ast::Expr;
24+
use crate::ast::Identifier;
2425
use crate::ast::TypeName;
2526

26-
#[derive(Debug, Clone, PartialEq, Eq, Drive, DriveMut)]
27+
#[derive(Debug, Clone, PartialEq, Drive, DriveMut)]
2728
pub struct ExecuteImmediateStmt {
28-
pub script: String,
29+
pub script: Expr,
2930
}
3031

3132
impl Display for ExecuteImmediateStmt {
3233
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
33-
write!(f, "EXECUTE IMMEDIATE $$\n{}\n$$", self.script)?;
34+
write!(f, "EXECUTE IMMEDIATE {}", self.script)?;
3435
Ok(())
3536
}
3637
}
@@ -170,7 +171,7 @@ impl Display for DescProcedureStmt {
170171

171172
#[derive(Debug, Clone, PartialEq, Drive, DriveMut)]
172173
pub struct CallProcedureStmt {
173-
pub name: String,
174+
pub name: Identifier,
174175
pub args: Vec<Expr>,
175176
}
176177

src/query/ast/src/ast/statements/script.rs

Lines changed: 66 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,47 @@ impl Display for ReturnItem {
115115
}
116116
}
117117

118+
#[derive(Debug, Clone, PartialEq)]
119+
pub struct DeclareCursor {
120+
pub span: Span,
121+
pub name: Identifier,
122+
pub stmt: Option<Statement>,
123+
pub resultset: Option<Identifier>,
124+
}
125+
126+
impl Display for DeclareCursor {
127+
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
128+
let DeclareCursor {
129+
name,
130+
stmt,
131+
resultset,
132+
..
133+
} = self;
134+
if let Some(stmt) = stmt {
135+
write!(f, "{name} CURSOR FOR {stmt}")
136+
} else if let Some(resultset) = resultset {
137+
write!(f, "{name} CURSOR FOR {resultset}")
138+
} else {
139+
write!(f, "{name} CURSOR")
140+
}
141+
}
142+
}
143+
144+
#[derive(Debug, Clone, PartialEq)]
145+
pub enum IterableItem {
146+
Resultset(Identifier),
147+
Cursor(Identifier),
148+
}
149+
150+
impl Display for IterableItem {
151+
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
152+
match self {
153+
IterableItem::Resultset(name) => write!(f, "{name}"),
154+
IterableItem::Cursor(name) => write!(f, "{name}"),
155+
}
156+
}
157+
}
158+
118159
#[derive(Debug, Clone, PartialEq)]
119160
pub enum ScriptStatement {
120161
LetVar {
@@ -123,6 +164,9 @@ pub enum ScriptStatement {
123164
LetStatement {
124165
declare: DeclareSet,
125166
},
167+
LetCursor {
168+
declare: DeclareCursor,
169+
},
126170
RunStatement {
127171
span: Span,
128172
stmt: Statement,
@@ -132,6 +176,19 @@ pub enum ScriptStatement {
132176
name: Identifier,
133177
value: Expr,
134178
},
179+
OpenCursor {
180+
span: Span,
181+
cursor: Identifier,
182+
},
183+
FetchCursor {
184+
span: Span,
185+
cursor: Identifier,
186+
into_var: Identifier,
187+
},
188+
CloseCursor {
189+
span: Span,
190+
cursor: Identifier,
191+
},
135192
Return {
136193
span: Span,
137194
value: Option<ReturnItem>,
@@ -148,7 +205,7 @@ pub enum ScriptStatement {
148205
ForInSet {
149206
span: Span,
150207
variable: Identifier,
151-
resultset: Identifier,
208+
iterable: IterableItem,
152209
body: Vec<ScriptStatement>,
153210
label: Option<Identifier>,
154211
},
@@ -204,8 +261,14 @@ impl Display for ScriptStatement {
204261
match self {
205262
ScriptStatement::LetVar { declare, .. } => write!(f, "LET {declare}"),
206263
ScriptStatement::LetStatement { declare, .. } => write!(f, "LET {declare}"),
264+
ScriptStatement::LetCursor { declare, .. } => write!(f, "LET {declare}"),
207265
ScriptStatement::RunStatement { stmt, .. } => write!(f, "{stmt}"),
208266
ScriptStatement::Assign { name, value, .. } => write!(f, "{name} := {value}"),
267+
ScriptStatement::OpenCursor { cursor, .. } => write!(f, "OPEN {cursor}"),
268+
ScriptStatement::FetchCursor {
269+
cursor, into_var, ..
270+
} => write!(f, "FETCH {cursor} INTO {into_var}"),
271+
ScriptStatement::CloseCursor { cursor, .. } => write!(f, "CLOSE {cursor}"),
209272
ScriptStatement::Return { value, .. } => {
210273
if let Some(value) = value {
211274
write!(f, "RETURN {value}")
@@ -242,12 +305,12 @@ impl Display for ScriptStatement {
242305
}
243306
ScriptStatement::ForInSet {
244307
variable,
245-
resultset,
308+
iterable,
246309
body,
247310
label,
248311
..
249312
} => {
250-
writeln!(f, "FOR {variable} IN {resultset} DO")?;
313+
writeln!(f, "FOR {variable} IN {iterable} DO")?;
251314
for stmt in body {
252315
writeln!(
253316
f,

src/query/ast/src/ast/statements/task.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ use crate::ast::quote::QuotedString;
2424
use crate::ast::write_comma_separated_string_list;
2525
use crate::ast::write_comma_separated_string_map;
2626
use crate::ast::Expr;
27+
use crate::ast::Identifier;
2728
use crate::ast::ShowLimit;
2829

2930
#[derive(Debug, Clone, PartialEq, Drive, DriveMut)]
@@ -370,7 +371,7 @@ impl Display for ShowTasksStmt {
370371

371372
#[derive(Debug, Clone, PartialEq, Drive, DriveMut)]
372373
pub struct ExecuteTaskStmt {
373-
pub name: String,
374+
pub name: Identifier,
374375
}
375376

376377
impl Display for ExecuteTaskStmt {
@@ -381,7 +382,7 @@ impl Display for ExecuteTaskStmt {
381382

382383
#[derive(Debug, Clone, PartialEq, Drive, DriveMut)]
383384
pub struct DescribeTaskStmt {
384-
pub name: String,
385+
pub name: Identifier,
385386
}
386387

387388
impl Display for DescribeTaskStmt {

src/query/ast/src/parser/script.rs

Lines changed: 135 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15+
use nom::branch::alt;
1516
use nom::combinator::consumed;
1617
use nom::combinator::map;
1718
use nom_rule::rule;
@@ -23,6 +24,25 @@ use crate::parser::input::Input;
2324
use crate::parser::statement::*;
2425
use crate::parser::token::*;
2526

27+
#[allow(clippy::large_enum_variant)]
28+
#[derive(Debug, Clone, PartialEq)]
29+
pub enum ScriptBlockOrStmt {
30+
ScriptBlock(ScriptBlock),
31+
Statement(Statement),
32+
}
33+
34+
pub fn script_block_or_stmt(i: Input) -> IResult<ScriptBlockOrStmt> {
35+
alt((
36+
map(script_block, ScriptBlockOrStmt::ScriptBlock),
37+
map(
38+
consumed(rule! {
39+
#statement
40+
}),
41+
|(_, stmt)| ScriptBlockOrStmt::Statement(stmt.stmt),
42+
),
43+
))(i)
44+
}
45+
2646
pub fn script_block(i: Input) -> IResult<ScriptBlock> {
2747
map(
2848
consumed(rule! {
@@ -79,6 +99,53 @@ pub fn declare_set(i: Input) -> IResult<DeclareSet> {
7999
)(i)
80100
}
81101

102+
pub fn declare_cursor(i: Input) -> IResult<DeclareCursor> {
103+
map(
104+
consumed(rule! {
105+
#ident ~ CURSOR ~ ^FOR ~ ^#cursor_target
106+
}),
107+
|(span, (name, _, _, target))| match target {
108+
CursorTarget::Resultset(resultset) => DeclareCursor {
109+
span: transform_span(span.tokens),
110+
name,
111+
stmt: None,
112+
resultset: Some(resultset),
113+
},
114+
CursorTarget::Statement(stmt) => DeclareCursor {
115+
span: transform_span(span.tokens),
116+
name,
117+
stmt: Some(stmt),
118+
resultset: None,
119+
},
120+
},
121+
)(i)
122+
}
123+
124+
#[allow(clippy::large_enum_variant)]
125+
#[derive(Debug, Clone, PartialEq)]
126+
pub(crate) enum CursorTarget {
127+
Resultset(Identifier),
128+
Statement(Statement),
129+
}
130+
131+
pub(crate) fn cursor_target(i: Input) -> IResult<CursorTarget> {
132+
// Try identifier first, then statement
133+
let resultset = map(ident, CursorTarget::Resultset);
134+
let statement = map(statement_body, CursorTarget::Statement);
135+
136+
rule!(
137+
#resultset
138+
| #statement
139+
)(i)
140+
}
141+
142+
pub(crate) fn iterable_item(i: Input) -> IResult<IterableItem> {
143+
// For now, we'll treat all identifiers as potential iterables
144+
// The compiler will determine if it's a cursor or resultset
145+
// based on what was actually declared
146+
map(ident, IterableItem::Resultset)(i)
147+
}
148+
82149
pub fn script_stmts(i: Input) -> IResult<Vec<ScriptStatement>> {
83150
semicolon_terminated_list1(script_stmt)(i)
84151
}
@@ -96,6 +163,40 @@ pub fn script_stmt(i: Input) -> IResult<ScriptStatement> {
96163
},
97164
|(_, declare)| ScriptStatement::LetStatement { declare },
98165
);
166+
let let_cursor_stmt = map(
167+
rule! {
168+
LET ~ #declare_cursor
169+
},
170+
|(_, declare)| ScriptStatement::LetCursor { declare },
171+
);
172+
let open_cursor_stmt = map(
173+
consumed(rule! {
174+
OPEN ~ #ident
175+
}),
176+
|(span, (_, cursor))| ScriptStatement::OpenCursor {
177+
span: transform_span(span.tokens),
178+
cursor,
179+
},
180+
);
181+
let fetch_cursor_stmt = map(
182+
consumed(rule! {
183+
FETCH ~ #ident ~ ^INTO ~ ^#ident
184+
}),
185+
|(span, (_, cursor, _, into_var))| ScriptStatement::FetchCursor {
186+
span: transform_span(span.tokens),
187+
cursor,
188+
into_var,
189+
},
190+
);
191+
let close_cursor_stmt = map(
192+
consumed(rule! {
193+
CLOSE ~ #ident
194+
}),
195+
|(span, (_, cursor))| ScriptStatement::CloseCursor {
196+
span: transform_span(span.tokens),
197+
cursor,
198+
},
199+
);
99200
let run_stmt = map(
100201
consumed(rule! {
101202
#statement_body
@@ -173,14 +274,14 @@ pub fn script_stmt(i: Input) -> IResult<ScriptStatement> {
173274
);
174275
let for_in_set_stmt = map(
175276
consumed(rule! {
176-
FOR ~ ^#ident ~ ^IN ~ #ident ~ ^DO
277+
FOR ~ ^#ident ~ ^IN ~ #iterable_item ~ ^DO
177278
~ ^#semicolon_terminated_list1(script_stmt)
178279
~ ^END ~ ^FOR ~ #ident?
179280
}),
180-
|(span, (_, variable, _, resultset, _, body, _, _, label))| ScriptStatement::ForInSet {
281+
|(span, (_, variable, _, iterable, _, body, _, _, label))| ScriptStatement::ForInSet {
181282
span: transform_span(span.tokens),
182283
variable,
183-
resultset,
284+
iterable,
184285
body,
185286
label,
186287
},
@@ -299,24 +400,48 @@ pub fn script_stmt(i: Input) -> IResult<ScriptStatement> {
299400
},
300401
);
301402

302-
rule!(
403+
let cursor_stmts = rule!(
404+
#let_cursor_stmt
405+
| #open_cursor_stmt
406+
| #fetch_cursor_stmt
407+
| #close_cursor_stmt
408+
);
409+
410+
let assignment_stmts = rule!(
303411
#let_stmt_stmt
304412
| #let_var_stmt
305-
| #run_stmt
306413
| #assign_stmt
307-
| #return_set_stmt
414+
);
415+
416+
let control_flow_stmts = rule!(
417+
#return_set_stmt
308418
| #return_stmt_stmt
309419
| #return_var_stmt
310420
| #return_stmt
311-
| #for_loop_stmt
421+
| #break_stmt
422+
| #continue_stmt
423+
);
424+
425+
let loop_stmts = rule!(
426+
#for_loop_stmt
312427
| #for_in_set_stmt
313428
| #for_in_stmt_stmt
314429
| #while_loop_stmt
315430
| #repeat_loop_stmt
316431
| #loop_stmt
317-
| #break_stmt
318-
| #continue_stmt
319-
| #case_stmt
432+
);
433+
434+
let conditional_stmts = rule!(
435+
#case_stmt
320436
| #if_stmt
437+
);
438+
439+
rule!(
440+
#assignment_stmts
441+
| #cursor_stmts
442+
| #control_flow_stmts
443+
| #loop_stmts
444+
| #conditional_stmts
445+
| #run_stmt
321446
)(i)
322447
}

0 commit comments

Comments
 (0)