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

schemadiff: validate and apply foreign key indexes #12026

Merged
merged 25 commits into from
Jan 29, 2023

Conversation

shlomi-noach
Copy link
Contributor

@shlomi-noach shlomi-noach commented Jan 1, 2023

Description

This PR extends both #11944 and #12016 (at this time both unmerged).

In this PR, schemadiff runs the following:

  • for every foreign key constraint, table validation verifies there's an appropriate index on the local table columns
  • for every foreign key constraint, schema validation verifies there's an appropriate index on the remote table columns
  • Apply()ing a ADD CONSTRAINT ... FOREIGN KEY auto-adds an appropriate index on the local table, if one does not exist. This is compliant with MySQL behavior.
  • A CREATE TABLE is normalized to have an implicit index, if need be, for every foreign key definition. This is compliant with MySQL behavior.

Tests added to validate new behavior.

Related Issue(s)

Checklist

  • "Backport to:" labels have been added if this change should be back-ported
  • Tests were added or are not required
  • Documentation was added or is not required

Deployment Notes

Signed-off-by: Shlomi Noach <2607934+shlomi-noach@users.noreply.github.com>
Signed-off-by: Shlomi Noach <2607934+shlomi-noach@users.noreply.github.com>
Signed-off-by: Shlomi Noach <2607934+shlomi-noach@users.noreply.github.com>
Signed-off-by: Shlomi Noach <2607934+shlomi-noach@users.noreply.github.com>
Signed-off-by: Shlomi Noach <2607934+shlomi-noach@users.noreply.github.com>
…nKeyColumnCountError, MismatchingForeignKeyColumnTypeError

Signed-off-by: Shlomi Noach <2607934+shlomi-noach@users.noreply.github.com>
…nstraint columns

Signed-off-by: Shlomi Noach <2607934+shlomi-noach@users.noreply.github.com>
Signed-off-by: Shlomi Noach <2607934+shlomi-noach@users.noreply.github.com>
Signed-off-by: Shlomi Noach <2607934+shlomi-noach@users.noreply.github.com>
Signed-off-by: Shlomi Noach <2607934+shlomi-noach@users.noreply.github.com>
…ition splits into 'id int' and 'primary key (id)' parts. Primary key is always the first key in the list of keys. Handle queries such as 'modify id int primary key' (validate there isn't already a primary key, or that the existing primary key is over 'id'. add column with primary key definition...

Signed-off-by: Shlomi Noach <2607934+shlomi-noach@users.noreply.github.com>
Signed-off-by: Shlomi Noach <2607934+shlomi-noach@users.noreply.github.com>
Signed-off-by: Shlomi Noach <2607934+shlomi-noach@users.noreply.github.com>
Signed-off-by: Shlomi Noach <2607934+shlomi-noach@users.noreply.github.com>
Signed-off-by: Shlomi Noach <2607934+shlomi-noach@users.noreply.github.com>
Signed-off-by: Shlomi Noach <2607934+shlomi-noach@users.noreply.github.com>
Signed-off-by: Shlomi Noach <2607934+shlomi-noach@users.noreply.github.com>
@vitess-bot
Copy link
Contributor

vitess-bot bot commented Jan 1, 2023

Review Checklist

Hello reviewers! 👋 Please follow this checklist when reviewing this Pull Request.

General

  • Ensure that the Pull Request has a descriptive title.
  • If this is a change that users need to know about, please apply the release notes (needs details) label so that merging is blocked unless the summary release notes document is included.
  • If a test is added or modified, there should be a documentation on top of the test to explain what the expected behavior is what the test does.

If a new flag is being introduced:

  • Is it really necessary to add this flag?
  • Flag names should be clear and intuitive (as far as possible)
  • Help text should be descriptive.
  • Flag names should use dashes (-) as word separators rather than underscores (_).

If a workflow is added or modified:

  • Each item in Jobs should be named in order to mark it as required.
  • If the workflow should be required, the maintainer team should be notified.

Bug fixes

  • There should be at least one unit or end-to-end test.
  • The Pull Request description should include a link to an issue that describes the bug.

Non-trivial changes

  • There should be some code comments as to why things are implemented the way they are.

New/Existing features

  • Should be documented, either by modifying the existing documentation or creating new documentation.
  • New features should have a link to a feature request issue or an RFC that documents the use cases, corner cases and test cases.

Backward compatibility

  • Protobuf changes should be wire-compatible.
  • Changes to _vt tables and RPCs need to be backward compatible.
  • vtctl command output order should be stable and awk-able.
  • RPC changes should be compatible with vitess-operator
  • If a flag is removed, then it should also be removed from VTop, if used there.

Signed-off-by: Shlomi Noach <2607934+shlomi-noach@users.noreply.github.com>
Signed-off-by: Shlomi Noach <2607934+shlomi-noach@users.noreply.github.com>
…smatchError

Signed-off-by: Shlomi Noach <2607934+shlomi-noach@users.noreply.github.com>
Signed-off-by: Shlomi Noach <2607934+shlomi-noach@users.noreply.github.com>
Signed-off-by: Shlomi Noach <2607934+shlomi-noach@users.noreply.github.com>
@shlomi-noach shlomi-noach marked this pull request as ready for review January 23, 2023 14:20
@shlomi-noach shlomi-noach changed the title *WIP* schemadiff: validate and apply foreign key indexes schemadiff: validate and apply foreign key indexes Jan 23, 2023
@shlomi-noach shlomi-noach requested review from dbussink and a team January 23, 2023 14:22
@shlomi-noach
Copy link
Contributor Author

Ready for review

…eded

Signed-off-by: Shlomi Noach <2607934+shlomi-noach@users.noreply.github.com>
sqlescape.EscapeID(e.Key),
sqlescape.EscapeID(e.Table),
)
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Hmm, I'm not sure why these are 3 different error types when they seem all pretty similar? Would it be simpler to model this as one?

The first two seem to be the case of there's an FK constraint to the table itself, but in that case I think it's ok if Table and ReferencedTable contain the same value?

Not sure about the 3rd one, but that seems to not have a constraint name and not sure when that happens? Don't we always have to generate a constraint name anyway if it's missing and would it be fine if that name was set then on the same error?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good catch on the 1st error, MissingForeignKeyIndexError: I've just removed it. It can never fire because, compatible with MySQL's behavior, we always add an index if one is needed, either in a CREATE TABLE statement or in a ALTER TABLE ... ADD ... FOREIGN KEY statement.

2nd error, MissingForeignKeyReferencedIndexError, is when the parent table does not have an index covering the referenced columns. Here, MySQL does not add anything implicitly, because that's on a different table. The error is compatible with MySQL.

3rd error, IndexNeededByForeignKeyError is for when you attempt to ALTER TABLE ... DROP KEY and when that leaves a foreign key without an index covering its local columns. Compatible with MySQL, that's an error.

for i, col := range columns {
// the index must cover same columns, in order, wih possibly more columns covered than requested.
indexCol := index.Columns[i]
if col.String() != indexCol.Column.String() {
Copy link
Contributor

Choose a reason for hiding this comment

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

Should this be case insensitive? So like using !strings.EqualFold instead of !=?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good catch, fixed

require.NoError(t, err)
tableColumns := map[string]sqlparser.IdentifierCI{}
for _, col := range c.CreateTable.TableSpec.Columns {
tableColumns[col.Name.String()] = col.Name
Copy link
Contributor

Choose a reason for hiding this comment

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

Should this be using strings.ToLower() as well? And should we extend the tests to have some more case mismatch cases to verify the behavior when those exist?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good catch, fixed, and added a test!

…n tests

Signed-off-by: Shlomi Noach <2607934+shlomi-noach@users.noreply.github.com>
…QL behavior, we implicitly add the index if missing

Signed-off-by: Shlomi Noach <2607934+shlomi-noach@users.noreply.github.com>
@shlomi-noach
Copy link
Contributor Author

Looking for a 2nd review/approval

Copy link
Contributor

@rohit-nayak-ps rohit-nayak-ps left a comment

Choose a reason for hiding this comment

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

lgtm

@shlomi-noach shlomi-noach merged commit ae8406d into vitessio:main Jan 29, 2023
@shlomi-noach shlomi-noach deleted the schemadiff-fk-keys branch January 29, 2023 12:40
dbussink pushed a commit that referenced this pull request Jan 30, 2023
* more testing for getViewDependentTableNames()



* getForeignKeyParentTableNames



* schema normalization: sort tables by fk reference order



* minor test addition



* ForeignKeyDependencyUnresolvedError



* InvalidReferencedColumnInForeignKeyConstraintError, MismatchingForeignKeyColumnCountError, MismatchingForeignKeyColumnTypeError



* validate or autogenerate index on local table based on foreign key constraint columns



* validate referenced table key



* ColumnKeyOption consts become public



* adding DuplicateKeyNameError



* normalize PRIMARY KEY definition: a 'id int primary key' column definition splits into 'id int' and 'primary key (id)' parts. Primary key is always the first key in the list of keys. Handle queries such as 'modify id int primary key' (validate there isn't already a primary key, or that the existing primary key is over 'id'. add column with primary key definition...



* further unit test adaptations



* adapting tests: adding required local index over foreign key columns



* implicitly add key over foreign key columns if no appropriate key exists



* normalize CREATE TABLE statement to include missing foreign key indexes



* rename error: ForeignKeyColumnCountMismatchError



* rename MismatchingForeignKeyColumnTypeError to ForeignKeyColumnTypeMismatchError



* changes per review



* add a few tests that validate an implicit index isn't added if not needed



* case insensitive column comparison in indexCoversColumnsInOrder and in tests



* MissingForeignKeyIndexError is not needed bcause, compatible with MySQL behavior, we implicitly add the index if missing



---------

Signed-off-by: Shlomi Noach <2607934+shlomi-noach@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Component: Query Serving Type: Enhancement Logical improvement (somewhere between a bug and feature)
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants