-
-
Notifications
You must be signed in to change notification settings - Fork 480
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
pick new viable underlying index for foreign keys when current one is dropped #4847
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good start, needs a little work
go/libraries/doltcore/sqle/tables.go
Outdated
return nil, nil, err | ||
} | ||
for _, fk := range fkc.AllKeys() { | ||
newIdx, ok, err := findIndexWithPrefix(t.sch, oldIdx.ColumnNames()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This isn't quite right: the old index being used might have had more column names than necessary for it to be used with this foreign key.
Consider parent (a, b, c)
, child (d, e, f)
. Parent table has an index on (a,b,c)
and (a,b)
. Child declares a foreign key constraint on d references parent (a)
. We'll use the index (a,b,c)
for it. When we drop index (a,b,c)
, we should fall back to (a,b)
. But this code doesn't do that, because it tries to use the old index columns, as opposed to the constraint definition.
Add a test.
newFk.ReferencedTableIndex = newIdx.Name() | ||
} else { | ||
// if a replacement index wasn't found; it matched on primary key, so use empty string | ||
newFk.ReferencedTableIndex = "" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also not good enough -- you can't make this assumption. If there is no index available to use after dropping this one, you have to raise an error.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we can make this assumption, because we do in other places like here and here.
This is because GMS also checks if a valid prefix index exists, and errors when there isn't (I updated the tests to confirm this behavior). In the case of switching to a PK as the underlying index, GMS actually considers PKs as indexes and will correctly not error. However, on dolt side, we don't treat PK as an index, so findIndexWithPrefix
wont be able to find it. A side effect of this is that if there is a viable PK and multiple viable secondary indexes, the PK will only be chosen if we drop all other viable secondary indexes first.
GMS Code for reference:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As long as there are tests then great
@@ -1186,6 +1186,90 @@ INSERT INTO child_non_unq VALUES ('1', 1), ('2', NULL), ('3', 3), ('4', 3), ('5' | |||
} | |||
} | |||
|
|||
func TestDropIndex(t *testing.T) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably better expressed as a Sql script test in ddl_queries.go
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think there are any queries that show what underlying secondary index a foreign key is using, which is why I wrote the tests here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I missed the explicit checks into foreign keys here, my fault.
There are some decent functional tests in GMS for this, so I think you're covered there.
But you don't have coverage for a bunch of scenarios you should be testing. Specifically, there aren't multiple indexes to choose from when you drop the existing one here.
A unit test for findIndexWithPrefix could be more effective for that, your call
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See comments
// setup | ||
root, err = ExecuteSql(dEnv, root, "create table parent (i int);") | ||
require.NoError(t, err) | ||
root, err = ExecuteSql(dEnv, root, "alter table parent add index (i);") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Name these indexes explicitly so that the names you use below don't break if we change the auto naming scheme
newFk.ReferencedTableIndex = newIdx.Name() | ||
} else { | ||
// if a replacement index wasn't found; it matched on primary key, so use empty string | ||
newFk.ReferencedTableIndex = "" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As long as there are tests then great
@@ -1186,6 +1186,90 @@ INSERT INTO child_non_unq VALUES ('1', 1), ('2', NULL), ('3', 3), ('4', 3), ('5' | |||
} | |||
} | |||
|
|||
func TestDropIndex(t *testing.T) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I missed the explicit checks into foreign keys here, my fault.
There are some decent functional tests in GMS for this, so I think you're covered there.
But you don't have coverage for a bunch of scenarios you should be testing. Specifically, there aren't multiple indexes to choose from when you drop the existing one here.
A unit test for findIndexWithPrefix could be more effective for that, your call
go/cmd/dolt/commands/indexcmds/ls.go
Outdated
@@ -113,6 +113,16 @@ func (cmd LsCmd) Exec(ctx context.Context, commandStr string, args []string, dEn | |||
} | |||
} | |||
|
|||
// TODO: delete this |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
?
require.NoError(t, err) | ||
|
||
// dropping secondary index ij, should choose ijk | ||
root, err = ExecuteSql(dEnv, root, "alter table parent drop index ij;") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this deterministic? Odd that it doesn't choose the primary key if suitable
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add a note that this isn't by design
require.NoError(t, err) | ||
|
||
// setup | ||
root, err = ExecuteSql(dEnv, root, "create table parent (i int);") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You have two separate test cases in this method. Name them and run them in t.Run() blocks
go/libraries/doltcore/sqle/tables.go
Outdated
@@ -1851,6 +1851,7 @@ func (t *AlterableDoltTable) CreateIndex(ctx *sql.Context, idx sql.IndexDef) err | |||
if err != nil { | |||
return err | |||
} | |||
// TODO: why do we need to do this? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
?
go/libraries/doltcore/sqle/tables.go
Outdated
@@ -1851,6 +1851,7 @@ func (t *AlterableDoltTable) CreateIndex(ctx *sql.Context, idx sql.IndexDef) err | |||
if err != nil { | |||
return err | |||
} | |||
// TODO: why do we need to do this? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, just a couple small comments and some code that probably should be removed before checkin
When dropping underlying secondary indexes used by foreign key, another existing viable one should be used in its place, unless there isn't one.
TODO: