@@ -1273,6 +1273,11 @@ impl<'a> Parser<'a> {
12731273 // SQLite has single-quoted identifiers
12741274 id_parts.push(Ident::with_quote('\'', s))
12751275 }
1276+ Token::Placeholder(s) => {
1277+ // Snowflake uses $1, $2, etc. for positional column references
1278+ // in staged data queries like: SELECT t.$1 FROM @stage t
1279+ id_parts.push(Ident::new(s))
1280+ }
12761281 Token::Mul => {
12771282 return Ok(Expr::QualifiedWildcard(
12781283 ObjectName::from(id_parts),
@@ -1898,6 +1903,13 @@ impl<'a> Parser<'a> {
18981903 chain.push(AccessExpr::Dot(expr));
18991904 self.advance_token(); // The consumed string
19001905 }
1906+ Token::Placeholder(s) => {
1907+ // Snowflake uses $1, $2, etc. for positional column references
1908+ // in staged data queries like: SELECT t.$1 FROM @stage t
1909+ let expr = Expr::Identifier(Ident::with_span(next_token.span, s));
1910+ chain.push(AccessExpr::Dot(expr));
1911+ self.advance_token(); // The consumed placeholder
1912+ }
19011913 // Fallback to parsing an arbitrary expression.
19021914 _ => match self.parse_subexpr(self.dialect.prec_value(Precedence::Period))? {
19031915 // If we get back a compound field access or identifier,
@@ -15103,6 +15115,11 @@ impl<'a> Parser<'a> {
1510315115 && self.peek_keyword_with_tokens(Keyword::SEMANTIC_VIEW, &[Token::LParen])
1510415116 {
1510515117 self.parse_semantic_view_table_factor()
15118+ } else if dialect_of!(self is SnowflakeDialect)
15119+ && self.peek_token_ref().token == Token::AtSign
15120+ {
15121+ // Snowflake stage reference: @mystage or @namespace.stage
15122+ self.parse_snowflake_stage_table_factor()
1510615123 } else {
1510715124 let name = self.parse_object_name(true)?;
1510815125
@@ -15199,6 +15216,35 @@ impl<'a> Parser<'a> {
1519915216 }
1520015217 }
1520115218
15219+ /// Parse a Snowflake stage reference as a table factor.
15220+ /// Handles syntax like: `@mystage1 (file_format => 'myformat', pattern => '...')`
15221+ fn parse_snowflake_stage_table_factor(&mut self) -> Result<TableFactor, ParserError> {
15222+ // Parse the stage name starting with @
15223+ let name = crate::dialect::parse_snowflake_stage_name(self)?;
15224+
15225+ // Parse optional stage options like (file_format => 'myformat', pattern => '...')
15226+ let args = if self.consume_token(&Token::LParen) {
15227+ Some(self.parse_table_function_args()?)
15228+ } else {
15229+ None
15230+ };
15231+
15232+ let alias = self.maybe_parse_table_alias()?;
15233+
15234+ Ok(TableFactor::Table {
15235+ name,
15236+ alias,
15237+ args,
15238+ with_hints: vec![],
15239+ version: None,
15240+ partitions: vec![],
15241+ with_ordinality: false,
15242+ json_path: None,
15243+ sample: None,
15244+ index_hints: vec![],
15245+ })
15246+ }
15247+
1520215248 fn maybe_parse_table_sample(&mut self) -> Result<Option<Box<TableSample>>, ParserError> {
1520315249 let modifier = if self.parse_keyword(Keyword::TABLESAMPLE) {
1520415250 TableSampleModifier::TableSample
0 commit comments