Skip to content

Redshift: Fix parsing for quoted numbered columns #1576

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 12 commits into from
Dec 15, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion src/dialect/redshift.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,19 @@ impl Dialect for RedshiftSqlDialect {
/// treating them as json path. If there is identifier then we assume
/// there is no json path.
fn is_proper_identifier_inside_quotes(&self, mut chars: Peekable<Chars<'_>>) -> bool {
// PartiQL (used as json path query language in Redshift) uses square bracket as a start character and a quote is a beginning of quoted identifier
if let Some(quote_start) = chars.peek() {
if *quote_start == '"' {
return true;
}
};
chars.next();
let mut not_white_chars = chars.skip_while(|ch| ch.is_whitespace()).peekable();
if let Some(&ch) = not_white_chars.peek() {
return self.is_identifier_start(ch);
// PartiQL uses single quote as starting identification inside a quote
// It is a normal identifier if it has no single quote at the beginning.
// Additionally square bracket can contain quoted identifier.
return ch == '"' || ch != '\'' && self.is_identifier_start(ch);
}
false
}
Expand Down
39 changes: 39 additions & 0 deletions tests/sqlparser_redshift.rs
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,31 @@ fn test_redshift_json_path() {
},
expr_from_projection(only(&select.projection))
);

let sql = r#"SELECT db1.sc1.tbl1.col1[0]."id" FROM customer_orders_lineitem"#;
let select = dialects.verified_only_select(sql);
assert_eq!(
&Expr::JsonAccess {
value: Box::new(Expr::CompoundIdentifier(vec![
Ident::new("db1"),
Ident::new("sc1"),
Ident::new("tbl1"),
Ident::new("col1")
])),
path: JsonPath {
path: vec![
JsonPathElem::Bracket {
key: Expr::Value(Value::Number("0".parse().unwrap(), false))
},
JsonPathElem::Dot {
key: "id".to_string(),
quoted: true,
}
]
}
},
expr_from_projection(only(&select.projection))
);
}

#[test]
Expand Down Expand Up @@ -353,3 +378,17 @@ fn test_parse_json_path_from() {
_ => panic!(),
}
}

#[test]
fn test_parse_select_numbered_columns() {
redshift_and_generic().verified_stmt(r#"SELECT 1 AS "1" FROM a"#);
// RedShift specific case - quoted identifier inside square bracket
redshift().verified_stmt(r#"SELECT 1 AS ["1"] FROM a"#);
}

#[test]
fn test_parse_create_numbered_columns() {
redshift_and_generic().verified_stmt(
r#"CREATE TABLE test_table_1 ("1" INT, "d" VARCHAR(155), "2" DOUBLE PRECISION)"#,
);
}
Loading