File tree Expand file tree Collapse file tree 11 files changed +123
-0
lines changed
tests/sqllogictests/suites/base/15_procedure Expand file tree Collapse file tree 11 files changed +123
-0
lines changed Original file line number Diff line number Diff line change @@ -207,6 +207,10 @@ pub enum ScriptStatement {
207207 span : Span ,
208208 value : Option < ReturnItem > ,
209209 } ,
210+ Throw {
211+ span : Span ,
212+ message : Option < Expr > ,
213+ } ,
210214 ForLoop {
211215 span : Span ,
212216 variable : Identifier ,
@@ -290,6 +294,13 @@ impl Display for ScriptStatement {
290294 write ! ( f, "RETURN" )
291295 }
292296 }
297+ ScriptStatement :: Throw { message, .. } => {
298+ if let Some ( message) = message {
299+ write ! ( f, "THROW {message}" )
300+ } else {
301+ write ! ( f, "THROW" )
302+ }
303+ }
293304 ScriptStatement :: ForLoop {
294305 variable,
295306 is_reverse,
Original file line number Diff line number Diff line change @@ -269,6 +269,15 @@ pub fn script_stmt(i: Input) -> IResult<ScriptStatement> {
269269 value : None ,
270270 } ,
271271 ) ;
272+ let throw_stmt = map (
273+ consumed ( rule ! {
274+ THROW ~ #expr?
275+ } ) ,
276+ |( span, ( _, message) ) | ScriptStatement :: Throw {
277+ span : transform_span ( span. tokens ) ,
278+ message,
279+ } ,
280+ ) ;
272281 let for_loop_stmt = map (
273282 consumed ( rule ! {
274283 FOR ~ ^#ident ~ ^IN ~ REVERSE ?
@@ -439,6 +448,7 @@ pub fn script_stmt(i: Input) -> IResult<ScriptStatement> {
439448 | #return_stmt_stmt
440449 | #return_var_stmt
441450 | #return_stmt
451+ | #throw_stmt
442452 | #break_stmt
443453 | #continue_stmt
444454 ) ;
Original file line number Diff line number Diff line change @@ -1240,6 +1240,8 @@ pub enum TokenKind {
12401240 TENANT ,
12411241 #[ token( "THEN" , ignore( ascii_case) ) ]
12421242 THEN ,
1243+ #[ token( "THROW" , ignore( ascii_case) ) ]
1244+ THROW ,
12431245 #[ token( "THURSDAY" , ignore( ascii_case) ) ]
12441246 THURSDAY ,
12451247 #[ token( "TIME" , ignore( ascii_case) ) ]
Original file line number Diff line number Diff line change @@ -1555,6 +1555,7 @@ fn test_script() {
15551555 r#"RETURN profit"# ,
15561556 r#"RETURN TABLE(t1)"# ,
15571557 r#"RETURN TABLE(select count(*) from t1)"# ,
1558+ r#"THROW 'Email already exists.'"# ,
15581559 r#"
15591560 FOR i IN REVERSE 1 TO maximum_count DO
15601561 counter := counter + 1;
Original file line number Diff line number Diff line change @@ -536,6 +536,28 @@ Return {
536536}
537537
538538
539+ ---------- Input ----------
540+ THROW 'Email already exists.'
541+ ---------- Output ---------
542+ THROW 'Email already exists.'
543+ ---------- AST ------------
544+ Throw {
545+ span: Some(
546+ 0..29,
547+ ),
548+ message: Some(
549+ Literal {
550+ span: Some(
551+ 6..29,
552+ ),
553+ value: String(
554+ "Email already exists.",
555+ ),
556+ },
557+ ),
558+ }
559+
560+
539561---------- Input ----------
540562FOR i IN REVERSE 1 TO maximum_count DO
541563 counter := counter + 1;
Original file line number Diff line number Diff line change @@ -193,6 +193,22 @@ impl Compiler {
193193 output. append ( & mut self . compile_sql_statement ( * span, stmt, to_set. clone ( ) ) ?) ;
194194 output. push ( ScriptIR :: ReturnSet { set : to_set } ) ;
195195 }
196+ ScriptStatement :: Throw { span, message } => {
197+ let mut throw_value = None ;
198+ if let Some ( expr) = message {
199+ let to_var = VarRef :: new_internal (
200+ expr. span ( ) ,
201+ "throw_value" ,
202+ & mut self . ref_allocator ,
203+ ) ;
204+ output. append ( & mut self . compile_expr ( expr, to_var. clone ( ) ) ?) ;
205+ throw_value = Some ( to_var) ;
206+ }
207+ output. push ( ScriptIR :: Throw {
208+ span : * span,
209+ message : throw_value,
210+ } ) ;
211+ }
196212 ScriptStatement :: ForLoop {
197213 span,
198214 variable,
Original file line number Diff line number Diff line change @@ -37,6 +37,7 @@ pub trait Client {
3737 -> Result < Self :: Var > ;
3838 fn num_rows ( & self , block : & Self :: Set ) -> usize ;
3939 fn is_true ( & self , scalar : & Self :: Var ) -> Result < bool > ;
40+ fn format_error ( & self , value : & Self :: Var ) -> Result < String > ;
4041}
4142
4243#[ derive( Debug , Clone ) ]
@@ -181,6 +182,15 @@ impl<C: Client> Executor<C> {
181182 self . return_value = Some ( ReturnValue :: Set ( self . get_set ( set) ?. clone ( ) ) ) ;
182183 self . goto_end ( ) ;
183184 }
185+ ScriptIR :: Throw { span, message } => {
186+ let msg = if let Some ( var) = message {
187+ let value = self . get_var ( var) ?;
188+ self . client . format_error ( value) ?
189+ } else {
190+ "Script threw an error" . to_string ( )
191+ } ;
192+ return Err ( ErrorCode :: ScriptExecutionError ( msg) . set_span ( * span) ) ;
193+ }
184194 }
185195
186196 self . pc += 1 ;
Original file line number Diff line number Diff line change @@ -93,6 +93,8 @@ pub enum ScriptIR {
9393 ReturnVar { var : VarRef } ,
9494 /// Returns a result set from the script.
9595 ReturnSet { set : SetRef } ,
96+ /// Throws an error from the script.
97+ Throw { span : Span , message : Option < VarRef > } ,
9698}
9799
98100impl Display for ScriptIR {
@@ -123,6 +125,13 @@ impl Display for ScriptIR {
123125 ScriptIR :: Return => write ! ( f, "RETURN" ) ?,
124126 ScriptIR :: ReturnVar { var } => write ! ( f, "RETURN {var}" ) ?,
125127 ScriptIR :: ReturnSet { set } => write ! ( f, "RETURN {set}" ) ?,
128+ ScriptIR :: Throw { message, .. } => {
129+ if let Some ( message) = message {
130+ write ! ( f, "THROW {message}" ) ?;
131+ } else {
132+ write ! ( f, "THROW" ) ?;
133+ }
134+ }
126135 } ;
127136 Ok ( ( ) )
128137 }
Original file line number Diff line number Diff line change @@ -696,6 +696,13 @@ impl Client for MockClient {
696696 fn is_true ( & self , scalar : & Self :: Var ) -> Result < bool > {
697697 Ok ( * scalar == Literal :: Boolean ( true ) )
698698 }
699+
700+ fn format_error ( & self , value : & Self :: Var ) -> Result < String > {
701+ Ok ( match value {
702+ Literal :: String ( s) => s. clone ( ) ,
703+ _ => value. to_string ( ) ,
704+ } )
705+ }
699706}
700707
701708#[ derive( Debug , Clone ) ]
Original file line number Diff line number Diff line change @@ -20,6 +20,7 @@ use databend_common_ast::parser::tokenize_sql;
2020use databend_common_ast:: parser:: Dialect ;
2121use databend_common_catalog:: catalog:: Catalog ;
2222use databend_common_exception:: ErrorCode ;
23+ use databend_common_expression:: display:: scalar_ref_to_string;
2324use databend_common_expression:: ComputedExpr ;
2425use databend_common_expression:: DataBlock ;
2526use databend_common_expression:: DataSchemaRef ;
@@ -217,6 +218,13 @@ impl Client for ScriptClient {
217218 ) ) ) ,
218219 }
219220 }
221+
222+ fn format_error ( & self , value : & Self :: Var ) -> databend_common_exception:: Result < String > {
223+ Ok ( match value {
224+ Scalar :: String ( s) => s. clone ( ) ,
225+ _ => scalar_ref_to_string ( & value. as_ref ( ) ) ,
226+ } )
227+ }
220228}
221229
222230#[ derive( serde:: Serialize ) ]
You can’t perform that action at this time.
0 commit comments