Skip to content
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

Find tables in using clause of delete statement #234

Merged
merged 3 commits into from
Nov 12, 2021
Merged
Show file tree
Hide file tree
Changes from all 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
6 changes: 6 additions & 0 deletions lib/pg_query/parse.rb
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,12 @@ def load_objects! # rubocop:disable Metrics/CyclomaticComplexity
subselect_items << statement.update_stmt.where_clause if statement.node == :update_stmt && statement.update_stmt.where_clause
subselect_items << statement.delete_stmt.where_clause if statement.node == :delete_stmt && statement.delete_stmt.where_clause

if statement.node == :delete_stmt
statement.delete_stmt.using_clause.each do |using_clause|
from_clause_items << { item: using_clause, type: :select }
end
end

if value.with_clause
cte_statements, cte_names = statements_and_cte_names_for_with_clause(value.with_clause)
@cte_names.concat(cte_names)
Expand Down
42 changes: 39 additions & 3 deletions spec/lib/parse_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1534,16 +1534,52 @@

it 'finds tables referenced in the FROM clause' do
query = described_class.parse(<<-SQL)
UPDATE users SET name = users_new.name FROM users_new WHERE users.id = users_new.id
UPDATE users SET name = users_new.name
FROM users_new
INNER JOIN join_table ON join_table.user_id = new_users.id
WHERE users.id = users_new.id
SQL
expect(query.warnings).to be_empty
expect(query.tables).to eq(['users', 'users_new'])
expect(query.select_tables).to eq(['users_new'])
expect(query.tables).to eq(['users', 'users_new', 'join_table'])
expect(query.select_tables).to eq(['users_new', 'join_table'])
Comment on lines +1543 to +1544
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This spec change is unrelated to the main change of the PR. I think the spec as written in this branch would have failed in a slightly older version of the code but now it is passing.

expect(query.dml_tables).to eq(['users'])
expect(query.ddl_tables).to eq([])
end
end

describe 'parsing DELETE' do
it 'finds the deleted table' do
query = described_class.parse(<<-SQL)
DELETE FROM users;
SQL
expect(query.warnings).to be_empty
expect(query.tables).to eq(['users'])
expect(query.dml_tables).to eq(['users'])
end

it 'finds the used table' do
query = described_class.parse(<<-SQL)
DELETE FROM users USING foo
WHERE foo_id = foo.id AND foo.action = 'delete';
SQL
expect(query.warnings).to be_empty
expect(query.tables).to eq(['users', 'foo'])
expect(query.dml_tables).to eq(['users'])
expect(query.select_tables).to eq(['foo'])
end

it 'finds the table in the where subquery' do
query = described_class.parse(<<-SQL)
DELETE FROM users
WHERE foo_id IN (SELECT id FROM foo WHERE action = 'delete');
SQL
expect(query.warnings).to be_empty
expect(query.tables).to eq(['users', 'foo'])
expect(query.dml_tables).to eq(['users'])
expect(query.select_tables).to eq(['foo'])
end
end

it 'handles DROP TYPE' do
query = described_class.parse("DROP TYPE IF EXISTS repack.pk_something")
expect(query.warnings).to eq []
Expand Down