fix(parser): accept string literal aliases after AS#22
Conversation
SQLite, MySQL, and Snowflake accept a string literal as a column or table alias (SELECT x AS 'My Alias'). The parser rejected it with "Expected identifier, got String". Accept a String token in alias position after an explicit AS and normalize it to QuoteStyle::DoubleQuote — the alias is an identifier despite the quoting, and the generator already re-quotes per target dialect. The implicit form (no AS) is intentionally not accepted, since a trailing string is concatenation in MySQL.
yigalrozenberg
left a comment
There was a problem hiding this comment.
Approved — small, focused, and correct. ✅
The key detail that makes this robust: the string-literal alias is returned as a quoted identifier (QuoteStyle::DoubleQuote) rather than an unquoted name, so it flows through write_quoted → QuoteStyle::for_dialect and emits the right quote style for every dialect family, with proper embedded-quote escaping:
- double-quote → PostgreSQL / Oracle / Snowflake / ANSI
- backtick → MySQL / BigQuery / Hive / Spark
- bracket → T-SQL / Fabric
Choosing quoted (not None) is exactly right — it preserves case under PG/Oracle/Snowflake folding. Gating strictly behind an explicit AS is also correct (a trailing string with no AS stays an expression / MySQL concatenation).
Verified locally: all 20 tests in test_quoted_aliases pass, no regressions across the test_transpile / test_dialects / test_expressions suites.
Merging with a few small maintainer follow-ups: broaden coverage with a T-SQL (bracket) test, a Snowflake case, and PG/Oracle transpile targets, and clarify the code comment (T-SQL also uses AS 'col', and the acceptance is intentionally dialect-agnostic / lenient on input). Thanks for the clean, well-tested fix!
…p to #22) - Add T-SQL (bracket), Snowflake, and PG/Oracle/T-SQL transpile tests so all three quote families are exercised, not just double-quote + backtick. - Clarify the comment: T-SQL also accepts AS 'col', and acceptance is intentionally dialect-agnostic / lenient on input.
|
🎉 Thanks so much for this contribution, @gauravs — a clean, focused, and well-tested fix. Really appreciate the thorough test cases (the escaped-quote and "no This has been merged to [dependencies]
sqlglot-rust = "0.10.11"I added a couple of small maintainer follow-ups on top of your change (commit
Thanks again for making the parser better! 🙌 |
Docs-only: adds the 'String-Literal Aliases' subsection to docs/reference.md, documenting the v0.10.11 feature (PR #22). No code changes.
Primarily the change is to support single quotes in column names. See protegrity/sql-glot-rust#22 for additional details.
…egrity#22 follow-up) Add a 'String-Literal Aliases' subsection to the QuoteStyle reference: AS 'x' is accepted for every dialect (lenient input) and normalized to the target dialect's canonical quoted identifier (double-quote / backtick / bracket) with case preserved. Examples are the exact outputs asserted by the test_single_quoted_alias_transpile_to_* tests. Follow-up to PR protegrity#22 (v0.10.11).
Problem
SQLite, MySQL, and Snowflake accept a string literal as a column or table
alias, but the parser rejects it:
This form is common in machine-generated SQL (e.g. ORMs that quote
display-name aliases as string literals).
Fix
parse_optional_alias now accepts a String token in alias position after
an explicit AS, for both column and table aliases. The alias is an
identifier despite the quoting, so it is normalized to
QuoteStyle::DoubleQuoteand the generator re-quotes it in each targetdialect's canonical style:
The implicit form (no AS, e.g. SELECT 'a' 'b') is intentionally not
accepted — adjacent string literals are concatenation in MySQL, so treating
a trailing string as an alias would silently change semantics.
Escaped quotes in the literal are handled by the tokenizer as usual
(AS 'It''s' → AS "It's").
Tests
Six new tests in tests/test_quoted_aliases.rs: column alias, table alias,
alias alongside quoted column refs, escaped inner quote, SQLite→MySQL
transpile, and a regression guard that a trailing string without AS
remains a string expression.