add support for CALL statements (#1063)

This commit is contained in:
Ophir LOJKINE 2023-12-19 21:01:44 +01:00 committed by GitHub
parent 8d97330d42
commit 1933f194e7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 89 additions and 11 deletions

View file

@ -1437,6 +1437,7 @@ pub enum Statement {
file_format: Option<FileFormat>, file_format: Option<FileFormat>,
source: Box<Query>, source: Box<Query>,
}, },
Call(Function),
Copy { Copy {
/// The source of 'COPY TO', or the target of 'COPY FROM' /// The source of 'COPY TO', or the target of 'COPY FROM'
source: CopySource, source: CopySource,
@ -1715,7 +1716,9 @@ pub enum Statement {
/// ///
/// Note: this is a PostgreSQL-specific statement, /// Note: this is a PostgreSQL-specific statement,
/// but may also compatible with other SQL. /// but may also compatible with other SQL.
Discard { object_type: DiscardObject }, Discard {
object_type: DiscardObject,
},
/// SET `[ SESSION | LOCAL ]` ROLE role_name. Examples: [ANSI][1], [Postgresql][2], [MySQL][3], and [Oracle][4]. /// SET `[ SESSION | LOCAL ]` ROLE role_name. Examples: [ANSI][1], [Postgresql][2], [MySQL][3], and [Oracle][4].
/// ///
/// [1]: https://jakewheat.github.io/sql-overview/sql-2016-foundation-grammar.html#set-role-statement /// [1]: https://jakewheat.github.io/sql-overview/sql-2016-foundation-grammar.html#set-role-statement
@ -1747,7 +1750,10 @@ pub enum Statement {
/// ///
/// Note: this is a PostgreSQL-specific statements /// Note: this is a PostgreSQL-specific statements
/// `SET TIME ZONE <value>` is an alias for `SET timezone TO <value>` in PostgreSQL /// `SET TIME ZONE <value>` is an alias for `SET timezone TO <value>` in PostgreSQL
SetTimeZone { local: bool, value: Expr }, SetTimeZone {
local: bool,
value: Expr,
},
/// SET NAMES 'charset_name' [COLLATE 'collation_name'] /// SET NAMES 'charset_name' [COLLATE 'collation_name']
/// ///
/// Note: this is a MySQL-specific statement. /// Note: this is a MySQL-specific statement.
@ -1762,13 +1768,17 @@ pub enum Statement {
/// SHOW FUNCTIONS /// SHOW FUNCTIONS
/// ///
/// Note: this is a Presto-specific statement. /// Note: this is a Presto-specific statement.
ShowFunctions { filter: Option<ShowStatementFilter> }, ShowFunctions {
filter: Option<ShowStatementFilter>,
},
/// ```sql /// ```sql
/// SHOW <variable> /// SHOW <variable>
/// ``` /// ```
/// ///
/// Note: this is a PostgreSQL-specific statement. /// Note: this is a PostgreSQL-specific statement.
ShowVariable { variable: Vec<Ident> }, ShowVariable {
variable: Vec<Ident>,
},
/// SHOW VARIABLES /// SHOW VARIABLES
/// ///
/// Note: this is a MySQL-specific statement. /// Note: this is a MySQL-specific statement.
@ -1806,11 +1816,15 @@ pub enum Statement {
/// SHOW COLLATION /// SHOW COLLATION
/// ///
/// Note: this is a MySQL-specific statement. /// Note: this is a MySQL-specific statement.
ShowCollation { filter: Option<ShowStatementFilter> }, ShowCollation {
filter: Option<ShowStatementFilter>,
},
/// USE /// USE
/// ///
/// Note: This is a MySQL-specific statement. /// Note: This is a MySQL-specific statement.
Use { db_name: Ident }, Use {
db_name: Ident,
},
/// `START [ TRANSACTION | WORK ] | START TRANSACTION } ...` /// `START [ TRANSACTION | WORK ] | START TRANSACTION } ...`
/// If `begin` is false. /// If `begin` is false.
/// ///
@ -1838,7 +1852,9 @@ pub enum Statement {
if_exists: bool, if_exists: bool,
}, },
/// `COMMIT [ TRANSACTION | WORK ] [ AND [ NO ] CHAIN ]` /// `COMMIT [ TRANSACTION | WORK ] [ AND [ NO ] CHAIN ]`
Commit { chain: bool }, Commit {
chain: bool,
},
/// `ROLLBACK [ TRANSACTION | WORK ] [ AND [ NO ] CHAIN ] [ TO [ SAVEPOINT ] savepoint_name ]` /// `ROLLBACK [ TRANSACTION | WORK ] [ AND [ NO ] CHAIN ] [ TO [ SAVEPOINT ] savepoint_name ]`
Rollback { Rollback {
chain: bool, chain: bool,
@ -1934,11 +1950,17 @@ pub enum Statement {
/// `DEALLOCATE [ PREPARE ] { name | ALL }` /// `DEALLOCATE [ PREPARE ] { name | ALL }`
/// ///
/// Note: this is a PostgreSQL-specific statement. /// Note: this is a PostgreSQL-specific statement.
Deallocate { name: Ident, prepare: bool }, Deallocate {
name: Ident,
prepare: bool,
},
/// `EXECUTE name [ ( parameter [, ...] ) ]` /// `EXECUTE name [ ( parameter [, ...] ) ]`
/// ///
/// Note: this is a PostgreSQL-specific statement. /// Note: this is a PostgreSQL-specific statement.
Execute { name: Ident, parameters: Vec<Expr> }, Execute {
name: Ident,
parameters: Vec<Expr>,
},
/// `PREPARE name [ ( data_type [, ...] ) ] AS statement` /// `PREPARE name [ ( data_type [, ...] ) ] AS statement`
/// ///
/// Note: this is a PostgreSQL-specific statement. /// Note: this is a PostgreSQL-specific statement.
@ -1979,9 +2001,13 @@ pub enum Statement {
format: Option<AnalyzeFormat>, format: Option<AnalyzeFormat>,
}, },
/// SAVEPOINT -- define a new savepoint within the current transaction /// SAVEPOINT -- define a new savepoint within the current transaction
Savepoint { name: Ident }, Savepoint {
name: Ident,
},
/// RELEASE \[ SAVEPOINT \] savepoint_name /// RELEASE \[ SAVEPOINT \] savepoint_name
ReleaseSavepoint { name: Ident }, ReleaseSavepoint {
name: Ident,
},
// MERGE INTO statement, based on Snowflake. See <https://docs.snowflake.com/en/sql-reference/sql/merge.html> // MERGE INTO statement, based on Snowflake. See <https://docs.snowflake.com/en/sql-reference/sql/merge.html>
Merge { Merge {
// optional INTO keyword // optional INTO keyword
@ -2303,6 +2329,8 @@ impl fmt::Display for Statement {
Ok(()) Ok(())
} }
Statement::Call(function) => write!(f, "CALL {function}"),
Statement::Copy { Statement::Copy {
source, source,
to, to,

View file

@ -493,6 +493,7 @@ impl<'a> Parser<'a> {
Keyword::UNCACHE => Ok(self.parse_uncache_table()?), Keyword::UNCACHE => Ok(self.parse_uncache_table()?),
Keyword::UPDATE => Ok(self.parse_update()?), Keyword::UPDATE => Ok(self.parse_update()?),
Keyword::ALTER => Ok(self.parse_alter()?), Keyword::ALTER => Ok(self.parse_alter()?),
Keyword::CALL => Ok(self.parse_call()?),
Keyword::COPY => Ok(self.parse_copy()?), Keyword::COPY => Ok(self.parse_copy()?),
Keyword::CLOSE => Ok(self.parse_close()?), Keyword::CLOSE => Ok(self.parse_close()?),
Keyword::SET => Ok(self.parse_set()?), Keyword::SET => Ok(self.parse_set()?),
@ -4773,6 +4774,32 @@ impl<'a> Parser<'a> {
}) })
} }
/// Parse a `CALL procedure_name(arg1, arg2, ...)`
/// or `CALL procedure_name` statement
pub fn parse_call(&mut self) -> Result<Statement, ParserError> {
let object_name = self.parse_object_name()?;
if self.peek_token().token == Token::LParen {
match self.parse_function(object_name)? {
Expr::Function(f) => Ok(Statement::Call(f)),
other => parser_err!(
format!("Expected a simple procedure call but found: {other}"),
self.peek_token().location
),
}
} else {
Ok(Statement::Call(Function {
name: object_name,
args: vec![],
over: None,
distinct: false,
filter: None,
null_treatment: None,
special: true,
order_by: vec![],
}))
}
}
/// Parse a copy statement /// Parse a copy statement
pub fn parse_copy(&mut self) -> Result<Statement, ParserError> { pub fn parse_copy(&mut self) -> Result<Statement, ParserError> {
let source; let source;

View file

@ -7949,6 +7949,29 @@ fn parse_create_type() {
); );
} }
#[test]
fn parse_call() {
all_dialects().verified_stmt("CALL my_procedure()");
all_dialects().verified_stmt("CALL my_procedure(1, 'a')");
pg_and_generic().verified_stmt("CALL my_procedure(1, 'a', $1)");
all_dialects().verified_stmt("CALL my_procedure");
assert_eq!(
verified_stmt("CALL my_procedure('a')"),
Statement::Call(Function {
args: vec![FunctionArg::Unnamed(FunctionArgExpr::Expr(Expr::Value(
Value::SingleQuotedString("a".to_string())
))),],
name: ObjectName(vec![Ident::new("my_procedure")]),
filter: None,
null_treatment: None,
over: None,
distinct: false,
special: false,
order_by: vec![]
})
);
}
#[test] #[test]
fn parse_create_table_collate() { fn parse_create_table_collate() {
pg_and_generic().verified_stmt("CREATE TABLE tbl (foo INT, bar TEXT COLLATE \"de_DE\")"); pg_and_generic().verified_stmt("CREATE TABLE tbl (foo INT, bar TEXT COLLATE \"de_DE\")");