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

Add support for partitioned indexes in PostgreSQL 11+ #37585

Merged
merged 1 commit into from Feb 6, 2020
Merged

Add support for partitioned indexes in PostgreSQL 11+ #37585

merged 1 commit into from Feb 6, 2020

Conversation

sebastian-palma
Copy link
Contributor

@sebastian-palma sebastian-palma commented Oct 29, 2019

This PR adds support to retrieve partitioned indexes when asking for indexes in a table.

Currently, the pg_class catalog is filtered out to retrieve the indexes in a
table by its relkind value. Which in versions lower than 11 of PostgreSQL
is always i (lower case). But since version 11, PostgreSQL
supports partitioned indexes referenced with a relkind value of I
(upper case). This makes any feature within the current code base to exclude those
partitioned indexes.

The solution proposed is to make use of the IN clause to filter those
relkind values of i and/or I when retrieving table indexes.

This adds the needed changes to cover the issue when performing an upsert_all with a partitioned table and a unique index in the parent table.

As index_name_exists? also performs the relkind = 'i' filter when asking for the indexes, it's been updated to reflect these changes.

@@ -503,6 +503,18 @@
t.column :weight, :integer
end

create_table(:measurements, id: false, force: true, options: "PARTITION BY LIST (city_id)") do |t|
Copy link
Contributor

Choose a reason for hiding this comment

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

This (and following) measurements table definitions in schema are valid only for postgres adapter.

CI can't create those tables on mysql and sqlite.

https://buildkite.com/rails/rails/builds/64610#b993a2df-ea4f-45f4-a6f2-0dd8487e2237
https://buildkite.com/rails/rails/builds/64610#8112f1a1-8b9e-4cf0-9b48-49f8caf5fb24

Any chance to make this table conditional and load coresponding model only when currently used adapter supports_partitioned_indexes?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hey @simi, thanks for the feedback. And yes, I'm gonna take a look at that, didn't check before if they were adapter constrained.

@@ -93,7 +93,7 @@ def indexes(table_name) # :nodoc:
INNER JOIN pg_index d ON t.oid = d.indrelid
INNER JOIN pg_class i ON d.indexrelid = i.oid
LEFT JOIN pg_namespace n ON n.oid = i.relnamespace
WHERE i.relkind = 'i'
Copy link
Contributor

Choose a reason for hiding this comment

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

🤔 We can hardcode IN ('i', 'I') for all versions here since it will not break older versions AFAIK.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm gonna try hardcoding the IN clause and running the test suite with older PG versions. I used PostgreSQL 11 to test this.

@@ -774,6 +774,11 @@ def quoted_scope(name = nil, type: nil)
scope
end

def relkind
Copy link
Contributor

Choose a reason for hiding this comment

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

🤔 There's already space before interpolation at WHERE i.relkind #{relkind}. There's no need to return string starting with space.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

If we hardcode the IN clause, we can get rid of this method 😉

@@ -3,6 +3,7 @@
require "cases/helper"
require "models/book"
require "models/speedometer"
require "models/measurement"
Copy link
Contributor

Choose a reason for hiding this comment

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

🤔 Maybe we can require this only in test_upsert_all_works_with_partitioned_indexes after the skip part since it will be used only there and for all other cases it will get loaded model having no real db table (since it is created conditionally).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That's a nice catch! And I think is a good idea, since there's only one test in the whole file making use of it.

BTW I tested the WHERE i.relkind IN ('i', 'I') changes in PostgreSQL 9.4, 9.6 and 10 (plus 11) and the test suite passes without problems.

@sebastian-palma
Copy link
Contributor Author

Hey @kamipo, could you take a look at this PR, please? I'm wondering if it can be merged in order to solve the problem stated in the description.

@kamipo
Copy link
Member

kamipo commented Dec 16, 2019

index_name_exists? also makes a query to pg_class asking for those rows relkind i only, but that's hasn't been changed.

Why?

@sebastian-palma
Copy link
Contributor Author

index_name_exists? also makes a query to pg_class asking for those rows relkind i only, but that's hasn't been changed.

Why?

I thought it'd make the PR "non-atomic" by trying to solve two things at once. Should I go with those changes?

@simi
Copy link
Contributor

simi commented Dec 16, 2019

@vnhnhm if you would like to add support for partitioned indexes of PostgreSQL adapter in general, you should fix all places needed. Your current change does fix only upsert_all part.

@@ -503,6 +503,20 @@
t.column :weight, :integer
end

if supports_partitioned_indexes?
Copy link
Contributor

Choose a reason for hiding this comment

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

🤔 I think you can move this to test/schema/postgresql_specific_schema.rb.

@sebastian-palma
Copy link
Contributor Author

@kamipo I've updated the code for index_name_exists? and added some test examples for that. @simi thanks for the clarification (;

@simi
Copy link
Contributor

simi commented Dec 27, 2019

@vnhnhm I think you should update the changelog entry title as well.

@sebastian-palma
Copy link
Contributor Author

It seems I did something wrong while trying to update the changelog, no @simi?

@simi
Copy link
Contributor

simi commented Dec 27, 2019

Try to rebase against latest master @vnhnhm.

@sebastian-palma
Copy link
Contributor Author

It looks better now, thanks @simi

@simi
Copy link
Contributor

simi commented Dec 27, 2019

Looks ok now. @kamipo any chance to take another look at this?

@@ -124,6 +124,10 @@ def supports_partial_index?
true
end

def supports_partitioned_indexes?
false
end
Copy link
Member

Choose a reason for hiding this comment

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

This shouldn't be necessary, since it's identical to the version in AbstractAdapter.

@@ -1,3 +1,7 @@
* Add support for PostgreSQL 11+ partitioned indexes when using `upsert-all`.
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
* Add support for PostgreSQL 11+ partitioned indexes when using `upsert-all`.
* Add support for PostgreSQL 11+ partitioned indexes when using `upsert_all`.

@sebastian-palma
Copy link
Contributor Author

Hey @eugeneius, just removed the changes from the SQLite3Adapter and updated the changelog as suggested, thanks!

Copy link
Contributor

@simi simi left a comment

Choose a reason for hiding this comment

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

looks good to me

PS: rebase would be nice

@sebastian-palma
Copy link
Contributor Author

looks good to me

PS: rebase would be nice

Yes, also to me :-). Thanks @simi

@kamipo
Copy link
Member

kamipo commented Feb 4, 2020

Can you squash your commits into one?

indexes in a table.

Currently the pg_class catalog is filtered out to retrieve the indexes in a
table by its relkind value. Which in versions lower than 11 of PostgreSQL
is always `i` (lower case). But since version 11, PostgreSQL
supports partitioned indexes referenced with a relkind value of `I`
(upper case). This makes any feature within the current code base to exclude those
partitioned indexes.

The solution proposed is to make use of the `IN` clause to filter those
relkind values of `i` and/or `I` when retrieving a table indexes.
@sebastian-palma
Copy link
Contributor Author

Sure, done @kamipo

@kamipo kamipo merged commit ee65181 into rails:master Feb 6, 2020
@sebastian-palma sebastian-palma deleted the upsert-all-partitioned-indexes branch February 6, 2020 09:07
@simi
Copy link
Contributor

simi commented Feb 6, 2020

🎉 thanks everone involved!

rafaelfranca pushed a commit that referenced this pull request Mar 30, 2020
…-indexes

Add support for partitioned indexes in PostgreSQL 11+
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants