Skip to content

Commit

Permalink
Postgres: CREATE COLLATION (#3571)
Browse files Browse the repository at this point in the history
* collate in table column

* Create collation

* delimited implies optional I guess

* Add note

* remove more optionals

* better tests

* Smush into a single test using UNIQUE instead of PK

* More tests

Co-authored-by: Barry Hart <barrywhart@yahoo.com>
Co-authored-by: Barry Pollard <barry_pollard@hotmail.com>
  • Loading branch information
3 people committed Jul 10, 2022
1 parent ec9af41 commit e365dcc
Show file tree
Hide file tree
Showing 6 changed files with 227 additions and 7 deletions.
71 changes: 65 additions & 6 deletions src/sqlfluff/dialects/dialect_postgres.py
Expand Up @@ -1420,13 +1420,16 @@ class CreateTableStatementSegment(ansi.CreateTableStatementSegment):
Sequence(
Ref("ColumnReferenceSegment"),
Ref("DatatypeSegment"),
Sequence(
"COLLATE",
Ref("QuotedLiteralSegment"),
optional=True,
),
AnyNumberOf(
Ref("ColumnConstraintSegment", optional=True)
# A single COLLATE segment can come before or after
# constraint segments
OneOf(
Ref("ColumnConstraintSegment"),
Sequence(
"COLLATE",
Ref("ObjectReferenceSegment"),
),
),
),
),
Ref("TableConstraintSegment"),
Expand Down Expand Up @@ -3318,6 +3321,7 @@ class StatementSegment(ansi.StatementSegment):
Ref("AlterTypeStatementSegment"),
Ref("AlterSchemaStatementSegment"),
Ref("LockTableStatementSegment"),
Ref("CreateCollationStatementSegment"),
],
)

Expand Down Expand Up @@ -4365,6 +4369,61 @@ class AlterTypeStatementSegment(BaseSegment):
)


class CreateCollationStatementSegment(BaseSegment):
"""A `CREATE COLLATION` statement.
https://www.postgresql.org/docs/current/sql-createcollation.html
"""

type = "create_collation_statement"
match_grammar: Matchable = Sequence(
"CREATE",
"COLLATION",
Ref("IfNotExistsGrammar", optional=True),
Ref("ObjectReferenceSegment"),
OneOf(
Bracketed(
Delimited(
Sequence(
"LOCALE",
Ref("EqualsSegment"),
Ref("QuotedLiteralSegment"),
),
Sequence(
"LC_COLLATE",
Ref("EqualsSegment"),
Ref("QuotedLiteralSegment"),
),
Sequence(
"LC_CTYPE",
Ref("EqualsSegment"),
Ref("QuotedLiteralSegment"),
),
Sequence(
"PROVIDER",
Ref("EqualsSegment"),
OneOf("ICU", "LIBC"),
),
Sequence(
"DETERMINISTIC",
Ref("EqualsSegment"),
Ref("BooleanLiteralGrammar"),
),
Sequence(
"VERSION",
Ref("EqualsSegment"),
Ref("QuotedLiteralSegment"),
),
)
),
Sequence(
"FROM",
Ref("ObjectReferenceSegment"),
),
),
)


class AlterSchemaStatementSegment(BaseSegment):
"""An `ALTER SCHEMA` statement.
Expand Down
4 changes: 4 additions & 0 deletions src/sqlfluff/dialects/dialect_postgres_keywords.py
Expand Up @@ -925,18 +925,21 @@ def get_keywords(keyword_list, keyword_type):
("DATE", "non-reserved"),
("DEPTH", "non-reserved"),
("DESCRIBE", "non-reserved"),
("DETERMINISTIC", "non-reserved"),
("EXTENDED", "non-reserved"),
("FILE", "non-reserved"),
("FORCE_NOT_NULL", "non-reserved"),
("FORCE_NULL", "non-reserved"),
("FORCE_QUOTE", "non-reserved"),
("FORMAT", "non-reserved"),
("HASH", "non-reserved"),
("ICU", "non-reserved"),
("IGNORE", "non-reserved"),
("IS_TEMPLATE", "non-reserved"),
("JSON", "non-reserved"),
("LC_COLLATE", "non-reserved"),
("LC_CTYPE", "non-reserved"),
("LIBC", "non-reserved"),
("LIST", "non-reserved"),
("LOGIN", "non-reserved"),
("LOCALE", "non-reserved"),
Expand All @@ -950,6 +953,7 @@ def get_keywords(keyword_list, keyword_type):
("NOREPLICATION", "non-reserved"),
("NOSUPERUSER", "non-reserved"),
("PLAIN", "non-reserved"),
("PROVIDER", "non-reserved"),
("PUBLIC", "non-reserved"),
("REMAINDER", "non-reserved"),
("REPLICATION", "non-reserved"),
Expand Down
7 changes: 7 additions & 0 deletions test/fixtures/dialects/postgres/postgres_create_collation.sql
@@ -0,0 +1,7 @@
CREATE COLLATION numeric (provider = icu, locale = 'en@colNumeric=yes');

CREATE COLLATION french (locale = 'fr_FR.utf8');

CREATE COLLATION german_phonebook (provider = icu, locale = 'de-u-co-phonebk');

CREATE COLLATION german FROM "de_DE";
69 changes: 69 additions & 0 deletions test/fixtures/dialects/postgres/postgres_create_collation.yml
@@ -0,0 +1,69 @@
# YML test files are auto-generated from SQL files and should not be edited by
# hand. To help enforce this, the "hash" field in the file must match a hash
# computed by SQLFluff when running the tests. Please run
# `python test/generate_parse_fixture_yml.py` to generate them after adding or
# altering SQL files.
_hash: 309835f67eb282ebe597717e51871c763cbc54e4501ca3bda650a877633f1023
file:
- statement:
create_collation_statement:
- keyword: CREATE
- keyword: COLLATION
- object_reference:
identifier: numeric
- bracketed:
- start_bracket: (
- keyword: provider
- comparison_operator:
raw_comparison_operator: '='
- keyword: icu
- comma: ','
- keyword: locale
- comparison_operator:
raw_comparison_operator: '='
- literal: "'en@colNumeric=yes'"
- end_bracket: )
- statement_terminator: ;
- statement:
create_collation_statement:
- keyword: CREATE
- keyword: COLLATION
- object_reference:
identifier: french
- bracketed:
start_bracket: (
keyword: locale
comparison_operator:
raw_comparison_operator: '='
literal: "'fr_FR.utf8'"
end_bracket: )
- statement_terminator: ;
- statement:
create_collation_statement:
- keyword: CREATE
- keyword: COLLATION
- object_reference:
identifier: german_phonebook
- bracketed:
- start_bracket: (
- keyword: provider
- comparison_operator:
raw_comparison_operator: '='
- keyword: icu
- comma: ','
- keyword: locale
- comparison_operator:
raw_comparison_operator: '='
- literal: "'de-u-co-phonebk'"
- end_bracket: )
- statement_terminator: ;
- statement:
create_collation_statement:
- keyword: CREATE
- keyword: COLLATION
- object_reference:
identifier: german
- keyword: FROM
- object_reference:
identifier: '"de_DE"'
- statement_terminator: ;
8 changes: 8 additions & 0 deletions test/fixtures/dialects/postgres/postgres_create_table.sql
Expand Up @@ -224,3 +224,11 @@ CREATE TABLE users (
domain_id INTEGER REFERENCES groups (group_id) ON UPDATE RESTRICT,
other_id INTEGER REFERENCES groups (group_id) MATCH SIMPLE
);

CREATE TABLE orders
(
id bigint NOT NULL DEFAULT NEXTVAL('orders_id_seq'::regclass),
constraint_collate_constraints text UNIQUE COLLATE numeric NOT NULL PRIMARY KEY,
constraints_collate text NOT NULL UNIQUE COLLATE numeric,
collate_constraints text COLLATE numeric NOT NULL UNIQUE
);
75 changes: 74 additions & 1 deletion test/fixtures/dialects/postgres/postgres_create_table.yml
Expand Up @@ -3,7 +3,7 @@
# computed by SQLFluff when running the tests. Please run
# `python test/generate_parse_fixture_yml.py` to generate them after adding or
# altering SQL files.
_hash: 1ce86226be391d0503f1a45ce8367faeb5628f17a241abc85aa0af4e308ef3f9
_hash: 15fd90958831ab1eeb765d759684c4f2521f9098f50e58befc6a29f31fcef957
file:
- statement:
create_table_statement:
Expand Down Expand Up @@ -1336,3 +1336,76 @@ file:
- keyword: SIMPLE
- end_bracket: )
- statement_terminator: ;
- statement:
create_table_statement:
- keyword: CREATE
- keyword: TABLE
- table_reference:
identifier: orders
- bracketed:
- start_bracket: (
- column_reference:
identifier: id
- data_type:
keyword: bigint
- column_constraint_segment:
- keyword: NOT
- keyword: 'NULL'
- column_constraint_segment:
keyword: DEFAULT
function:
function_name:
function_name_identifier: NEXTVAL
bracketed:
start_bracket: (
expression:
literal: "'orders_id_seq'"
cast_expression:
casting_operator: '::'
data_type:
data_type_identifier: regclass
end_bracket: )
- comma: ','
- column_reference:
identifier: constraint_collate_constraints
- data_type:
keyword: text
- column_constraint_segment:
keyword: UNIQUE
- keyword: COLLATE
- object_reference:
identifier: numeric
- column_constraint_segment:
- keyword: NOT
- keyword: 'NULL'
- column_constraint_segment:
- keyword: PRIMARY
- keyword: KEY
- comma: ','
- column_reference:
identifier: constraints_collate
- data_type:
keyword: text
- column_constraint_segment:
- keyword: NOT
- keyword: 'NULL'
- column_constraint_segment:
keyword: UNIQUE
- keyword: COLLATE
- object_reference:
identifier: numeric
- comma: ','
- column_reference:
identifier: collate_constraints
- data_type:
keyword: text
- keyword: COLLATE
- object_reference:
identifier: numeric
- column_constraint_segment:
- keyword: NOT
- keyword: 'NULL'
- column_constraint_segment:
keyword: UNIQUE
- end_bracket: )
- statement_terminator: ;

0 comments on commit e365dcc

Please sign in to comment.