File tree Expand file tree Collapse file tree
Expand file tree Collapse file tree Original file line number Diff line number Diff line change @@ -1115,6 +1115,13 @@ pub trait Dialect: Debug + Any {
11151115 false
11161116 }
11171117
1118+ /// Returns true if this dialect accepts a colon placeholder as a
1119+ /// `SELECT ... INTO` target, e.g. `SELECT ... INTO :var` in Snowflake
1120+ /// scripting, where the target is a local variable rather than a table.
1121+ fn supports_select_into_placeholder_target ( & self ) -> bool {
1122+ false
1123+ }
1124+
11181125 /// Returns true if this dialect supports `$` as a prefix for money literals
11191126 /// e.g. `SELECT $123.45` (SQL Server)
11201127 fn supports_dollar_as_money_prefix ( & self ) -> bool {
Original file line number Diff line number Diff line change @@ -195,6 +195,12 @@ impl Dialect for SnowflakeDialect {
195195 true
196196 }
197197
198+ /// Snowflake scripting accepts `SELECT ... INTO :var` where the target is a
199+ /// local variable placeholder rather than a table name.
200+ fn supports_select_into_placeholder_target ( & self ) -> bool {
201+ true
202+ }
203+
198204 /// See <https://docs.snowflake.com/en/developer-guide/snowflake-scripting/cursors>
199205 fn supports_for_loop_over_cursor ( & self ) -> bool {
200206 true
Original file line number Diff line number Diff line change @@ -20606,7 +20606,20 @@ impl<'a> Parser<'a> {
2060620606 .is_some();
2060720607 let unlogged = self.parse_keyword(Keyword::UNLOGGED);
2060820608 let table = self.parse_keyword(Keyword::TABLE);
20609- let name = self.parse_object_name(false)?;
20609+ let name = if self.dialect.supports_select_into_placeholder_target()
20610+ && self.peek_token_ref().token == Token::Colon
20611+ {
20612+ // Snowflake scripting: `SELECT ... INTO :var` targets a local
20613+ // variable. Keep the `:name` placeholder text as the object-name
20614+ // part so the round-trip is preserved and downstream can tell it
20615+ // apart from a bare table target.
20616+ let placeholder = self.parse_value()?;
20617+ ObjectName(vec![ObjectNamePart::Identifier(Ident::new(
20618+ placeholder.to_string(),
20619+ ))])
20620+ } else {
20621+ self.parse_object_name(false)?
20622+ };
2061020623
2061120624 Ok(SelectInto {
2061220625 temporary,
Original file line number Diff line number Diff line change @@ -8625,3 +8625,29 @@ fn test_show_terse_stages() {
86258625 _ => unreachable ! ( ) ,
86268626 }
86278627}
8628+
8629+ #[ test]
8630+ fn test_select_into_placeholder_target ( ) {
8631+ // Snowflake scripting: a colon placeholder is a valid `SELECT ... INTO`
8632+ // target (a local variable), and it round-trips as `:res`.
8633+ let stmt = snowflake ( ) . verified_stmt ( "SELECT :res + t.hmy INTO :res FROM tbl AS t" ) ;
8634+ let Statement :: Query ( query) = stmt else {
8635+ unreachable ! ( )
8636+ } ;
8637+ let SetExpr :: Select ( select) = * query. body else {
8638+ unreachable ! ( )
8639+ } ;
8640+ let into = select. into . expect ( "expected SELECT ... INTO clause" ) ;
8641+ assert_eq ! ( into. name. to_string( ) , ":res" ) ;
8642+ assert ! ( !into. table) ;
8643+
8644+ // Bare-identifier targets are unaffected.
8645+ let stmt = snowflake ( ) . verified_stmt ( "SELECT 1 INTO res FROM tbl" ) ;
8646+ let Statement :: Query ( query) = stmt else {
8647+ unreachable ! ( )
8648+ } ;
8649+ let SetExpr :: Select ( select) = * query. body else {
8650+ unreachable ! ( )
8651+ } ;
8652+ assert_eq ! ( select. into. unwrap( ) . name. to_string( ) , "res" ) ;
8653+ }
You can’t perform that action at this time.
0 commit comments