PostgreSQL: Support SQL standard ARRAY keyword in type declarations#2356
Conversation
|
Hit this same limitation independently: production Flyway migrations using the SQL-standard keyword form on a user-defined type ( 1. Enable it for GenericDialect. The README asks for dialect-specific syntax to be accepted by both the relevant dialect and GenericDialect, and the bracket form's // src/dialect/generic.rs
+ fn supports_array_typedef_with_keyword(&self) -> bool {
+ true
+ }2. Widen the tests. The current tests cover built-in element types in CREATE TABLE and CAST. These cases exercise different paths (custom and schema-qualified type names, ALTER TABLE, parenthesized typmods, and the suffix-vs-constructor ambiguity) and are worth pinning: pg_and_generic().verified_stmt("CREATE TABLE t (c currency ARRAY)");
pg_and_generic().verified_stmt("CREATE TABLE t (c public.currency ARRAY)");
pg_and_generic().verified_stmt("ALTER TABLE t ADD COLUMN c currency ARRAY");
pg_and_generic().verified_stmt("CREATE TABLE t (c NUMERIC(10,2) ARRAY)");
pg_and_generic().verified_stmt("CREATE TABLE t (c INT ARRAY DEFAULT ARRAY[]::INT[])");( Can send both as a patch against your branch if that's easier. |
|
@iffyio could you check this out when you have time? |
| /// Keyword style with an optional size, e.g. `INT ARRAY` or `INT ARRAY[4]`. | ||
| Keyword(Box<DataType>, Option<u64>), |
There was a problem hiding this comment.
| /// Keyword style with an optional size, e.g. `INT ARRAY` or `INT ARRAY[4]`. | |
| Keyword(Box<DataType>, Option<u64>), | |
| /// Qualified by a data type and optional size, e.g. `INT ARRAY` or `INT ARRAY[4]`. | |
| Qualified(Box<DataType>, Option<u64>), |
There was a problem hiding this comment.
Renamed the variant and propagated it
| true | ||
| } | ||
|
|
||
| fn supports_array_typedef_with_keyword(&self) -> bool { |
There was a problem hiding this comment.
| fn supports_array_typedef_with_keyword(&self) -> bool { | |
| fn supports_type_qualified_array(&self) -> bool { |
actually I wonder can we have the parser always accept the syntax (it doesnt seem like it would be ambiguous)?
There was a problem hiding this comment.
I generally tend to prefer keeping things as strict as possible, but I understand the general mantra of this parser is permissiveness.
I dropped supports_array_typedef_with_keyword entirely and now accept T ARRAY / T ARRAY[n] in every dialect. The bracket form stays gated since [ clashes with identifier quoting in MSSQL and SQLite, but the ARRAY keyword has no such clash.
This means that every dialect now also parses T ARRAY[4], including MySQL where only the bare T ARRAY is real SQL. No test treats that as an error, and I am not sure whether this is a good choice or not.
Again, I understand I tend to lean on strictness so maybe I am worrying over nothing. LMK your opinion.
| // A trailing `ARRAY` keyword makes the target an array type, e.g. MySQL's | ||
| // `CAST(... AS UNSIGNED ARRAY)`. PostgreSQL already consumes it while | ||
| // parsing the data type, so the guard avoids wrapping it twice. | ||
| if !matches!(data_type, DataType::Array(_)) && self.parse_keyword(Keyword::ARRAY) { | ||
| data_type = DataType::Array(ArrayElemTypeDef::Keyword(Box::new(data_type), None)); | ||
| } |
There was a problem hiding this comment.
not sure I follow the intent here, I imagined parse_data_type() already should produce the new variant here, removing the need for any special handling?
There was a problem hiding this comment.
That guard existed because the keyword form used to be gated off for MySQL, see #2356 (comment)
iffyio
left a comment
There was a problem hiding this comment.
Thanks @LucaCappelletti94 just a minor cleanup comment, otherwise I think this looks good
Co-authored-by: Ifeanyi Ubah <ify1992@yahoo.com>
iffyio
left a comment
There was a problem hiding this comment.
LGTM! Thanks @LucaCappelletti94!
Adds support for the SQL standard
ARRAYkeyword in array type declarations, such asINTEGER ARRAYandINTEGER ARRAY[4], which PostgreSQL accepts anywhere a type is expected (column definitions, casts, and the::operator). It is gated behind a newDialect::supports_array_typedef_with_keywordmethod, enabled for PostgreSQL, and the keyword form with its optional cardinality is represented by a newArrayElemTypeDef::Keywordvariant.This also unifies the existing MySQL multi-valued index syntax
CAST(... AS UNSIGNED ARRAY). Thearray: boolfield onExpr::Castis removed and the trailingARRAYkeyword is now captured throughArrayElemTypeDef::Keywordfor every dialect, so this is a breaking change to the AST. Parser behavior is unchanged for all dialects, only the representation is unified, and round-trip serialization is preserved.