Skip to content

Commit

Permalink
Support snowflake double dot notation for object name (apache#1540)
Browse files Browse the repository at this point in the history
  • Loading branch information
ayman-sigma authored Nov 30, 2024
1 parent 96f7c02 commit f4f112d
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 0 deletions.
10 changes: 10 additions & 0 deletions src/dialect/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,16 @@ pub trait Dialect: Debug + Any {
self.supports_trailing_commas()
}

/// Returns true if the dialect supports double dot notation for object names
///
/// Example
/// ```sql
/// SELECT * FROM db_name..table_name
/// ```
fn supports_object_name_double_dot_notation(&self) -> bool {
false
}

/// Dialect-specific infix parser override
///
/// This method is called to parse the next infix expression.
Expand Down
8 changes: 8 additions & 0 deletions src/dialect/snowflake.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,14 @@ impl Dialect for SnowflakeDialect {
true
}

// Snowflake supports double-dot notation when the schema name is not specified
// In this case the default PUBLIC schema is used
//
// see https://docs.snowflake.com/en/sql-reference/name-resolution#resolution-when-schema-omitted-double-dot-notation
fn supports_object_name_double_dot_notation(&self) -> bool {
true
}

fn is_identifier_part(&self, ch: char) -> bool {
ch.is_ascii_lowercase()
|| ch.is_ascii_uppercase()
Expand Down
7 changes: 7 additions & 0 deletions src/parser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8457,6 +8457,13 @@ impl<'a> Parser<'a> {
pub fn parse_object_name(&mut self, in_table_clause: bool) -> Result<ObjectName, ParserError> {
let mut idents = vec![];
loop {
if self.dialect.supports_object_name_double_dot_notation()
&& idents.len() == 1
&& self.consume_token(&Token::Period)
{
// Empty string here means default schema
idents.push(Ident::new(""));
}
idents.push(self.parse_identifier(in_table_clause)?);
if !self.consume_token(&Token::Period) {
break;
Expand Down
32 changes: 32 additions & 0 deletions tests/sqlparser_snowflake.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2866,3 +2866,35 @@ fn test_projection_with_nested_trailing_commas() {
let sql = "SELECT a, b, FROM c, (SELECT d, e, FROM f, LATERAL FLATTEN(input => events))";
let _ = snowflake().parse_sql_statements(sql).unwrap();
}

#[test]
fn test_sf_double_dot_notation() {
snowflake().verified_stmt("SELECT * FROM db_name..table_name");
snowflake().verified_stmt("SELECT * FROM x, y..z JOIN a..b AS b ON x.id = b.id");

assert_eq!(
snowflake()
.parse_sql_statements("SELECT * FROM X.Y..")
.unwrap_err()
.to_string(),
"sql parser error: Expected: identifier, found: ."
);
assert_eq!(
snowflake()
.parse_sql_statements("SELECT * FROM X..Y..Z")
.unwrap_err()
.to_string(),
"sql parser error: Expected: identifier, found: ."
);
assert_eq!(
// Ensure we don't parse leading token
snowflake()
.parse_sql_statements("SELECT * FROM .X.Y")
.unwrap_err()
.to_string(),
"sql parser error: Expected: identifier, found: ."
);
}

#[test]
fn test_parse_double_dot_notation_wrong_position() {}

0 comments on commit f4f112d

Please sign in to comment.