Skip to content

Commit

Permalink
Postgres: Complete DELETE FROM grammar (#2791)
Browse files Browse the repository at this point in the history
* Postgres: Complete DELETE FROM grammar

* Add DELETE statement to WITH grammar

* Add WITH RECURSIVE example

Co-authored-by: Barry Pollard <barry@tunetheweb.com>
  • Loading branch information
jpy-git and tunetheweb committed Mar 6, 2022
1 parent 9717038 commit c19c5b2
Show file tree
Hide file tree
Showing 4 changed files with 411 additions and 109 deletions.
1 change: 1 addition & 0 deletions src/sqlfluff/dialects/dialect_ansi.py
Expand Up @@ -2159,6 +2159,7 @@ class SelectStatementSegment(BaseSegment):
NonWithNonSelectableGrammar=OneOf(
Ref("UpdateStatementSegment"),
Ref("InsertStatementSegment"),
Ref("DeleteStatementSegment"),
),
# Things that behave like select statements, which can form part of set expressions.
NonSetSelectableGrammar=OneOf(
Expand Down
63 changes: 21 additions & 42 deletions src/sqlfluff/dialects/dialect_postgres.py
Expand Up @@ -3671,40 +3671,6 @@ class ValuesClauseSegment(BaseSegment):
)


@postgres_dialect.segment()
class DeleteUsingClauseSegment(BaseSegment):
"""USING clause."""

type = "using_clause"
match_grammar = StartsWith(
"USING",
terminator="WHERE",
enforce_whitespace_preceding_terminator=True,
)

parse_grammar = Sequence(
"USING",
Indent,
Delimited(
Ref("TableExpressionSegment"),
),
Dedent,
)


@postgres_dialect.segment()
class FromClauseTerminatingUsingWhereSegment(
ansi_dialect.get_segment("FromClauseSegment") # type: ignore
):
"""Copy `FROM` terminator statement to support `USING` in specific circumstances."""

match_grammar = StartsWith(
"FROM",
terminator=OneOf(Ref.keyword("USING"), Ref.keyword("WHERE")),
enforce_whitespace_preceding_terminator=True,
)


@postgres_dialect.segment(replace=True)
class DeleteStatementSegment(BaseSegment):
"""A `DELETE` statement.
Expand All @@ -3713,14 +3679,26 @@ class DeleteStatementSegment(BaseSegment):
"""

type = "delete_statement"
# TODO Implement WITH RECURSIVE
match_grammar = StartsWith("DELETE")
parse_grammar = Sequence(
"DELETE",
"FROM",
Ref.keyword("ONLY", optional=True),
Ref("FromClauseTerminatingUsingWhereSegment"),
# TODO Implement Star and As Alias
Ref("DeleteUsingClauseSegment", optional=True),
Ref("TableReferenceSegment"),
Ref("StarSegment", optional=True),
Ref("AsAliasExpressionSegment", optional=True),
Sequence(
"USING",
Indent,
Delimited(
Sequence(
Ref("TableExpressionSegment"),
Ref("AsAliasExpressionSegment", optional=True),
),
),
Dedent,
optional=True,
),
OneOf(
Sequence("WHERE", "CURRENT", "OF", Ref("ObjectReferenceSegment")),
Ref("WhereClauseSegment"),
Expand All @@ -3730,11 +3708,12 @@ class DeleteStatementSegment(BaseSegment):
"RETURNING",
OneOf(
Ref("StarSegment"),
Sequence(
Ref("ExpressionSegment"),
Ref("AliasSegment", optional=True),
Delimited(
Sequence(
Ref("ExpressionSegment"),
Ref("AsAliasExpressionSegment", optional=True),
),
),
optional=True,
),
optional=True,
),
Expand Down
41 changes: 35 additions & 6 deletions test/fixtures/dialects/postgres/postgres_delete.sql
@@ -1,12 +1,41 @@
DELETE FROM films WHERE kind <> 'Musical';

DELETE FROM films;

DELETE FROM tasks WHERE status = 'DONE' RETURNING *;
DELETE FROM ONLY films;

DELETE FROM films *;

DELETE FROM films AS f;

DELETE FROM films USING producers
WHERE producer_id = producers.id AND producers.name = 'foo';

DELETE FROM films AS f USING producers AS p
WHERE f.producer_id = p.id AND p.name = 'foo';

DELETE FROM films AS f USING producers AS p, actors AS a
WHERE f.producer_id = p.id AND p.name = 'foo'
AND f.actor_id = a.id AND a.name = 'joe cool';

DELETE FROM tasks WHERE CURRENT OF c_tasks;

DELETE FROM some_table
USING other_table
WHERE other_table.col = some_table.col
DELETE FROM films WHERE kind <> 'Musical';

DELETE FROM tasks WHERE status = 'DONE' RETURNING *;

DELETE FROM tasks WHERE status = 'DONE' RETURNING actor_id;

DELETE FROM tasks WHERE status = 'DONE' RETURNING actor_id as a_id;

DELETE FROM tasks WHERE status = 'DONE' RETURNING actor_id, producer_id;

DELETE FROM tasks WHERE status = 'DONE' RETURNING actor_id as a_id, producer_id as p_id;

WITH test as (select foo from bar)
DELETE FROM films;

WITH RECURSIVE t(n) AS (
VALUES (1)
UNION ALL
SELECT n+1 FROM t WHERE n < 100
)
DELETE FROM films;

0 comments on commit c19c5b2

Please sign in to comment.