-
Notifications
You must be signed in to change notification settings - Fork 3.8k
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
sql/schemachanger: implemented ALTER PRIMARY KEY for vanilla case #84514
sql/schemachanger: implemented ALTER PRIMARY KEY for vanilla case #84514
Conversation
"github.com/cockroachdb/errors" | ||
) | ||
|
||
// The implementation of `ALTER PRIMARY KEY` will be broken into multiple PRs: |
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 plan belongs in an issue and not in the code.
// 2. Consider the case where the new primary key is requested to be sharded. | ||
// 3. Consider the case where the old primary index is on the implicitly created `rowid` column, | ||
// in which case we also need to drop that column; | ||
// 4. Consider the case where altering primary key requires us to modify existing secondary indexes |
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 step deserves to come before the rowid changes we don't currently support.
oldPrimaryIndexElem := mustRetrievePrimaryIndexElement(tableElems, tn.String()) | ||
oldPrimaryIndexNameElem := mustRetrievePrimaryIndexNameElem(tableElems, oldPrimaryIndexElem.IndexID, tn.String()) | ||
|
||
// Resolve and drop elements from the old primary index |
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.
How does this compose with adding or dropping columns? Let's look at this together tomorrow afternoon. In the meantime, can I encourage you to read the DROP COLUMN PR
ea59185
to
e8cb163
Compare
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.
Reviewable status: complete! 0 of 0 LGTMs obtained (waiting on @ajwerner)
pkg/sql/schemachanger/scbuild/internal/scbuildstmt/alter_table_alter_primary_key.go
line 31 at r2 (raw file):
Previously, ajwerner wrote…
This plan belongs in an issue and not in the code.
done
pkg/sql/schemachanger/scbuild/internal/scbuildstmt/alter_table_alter_primary_key.go
line 36 at r2 (raw file):
Previously, ajwerner wrote…
This step deserves to come before the rowid changes we don't currently support.
ack
pkg/sql/schemachanger/scbuild/internal/scbuildstmt/alter_table_alter_primary_key.go
line 60 at r2 (raw file):
Previously, ajwerner wrote…
How does this compose with adding or dropping columns? Let's look at this together tomorrow afternoon. In the meantime, can I encourage you to read the DROP COLUMN PR
ack
4d0080d
to
6ffbfcf
Compare
if constraintName.ConstraintID >= ret { | ||
ret = constraintName.ConstraintID + 1 | ||
} | ||
}) |
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.
Drive-by reviewing: you should be able to walk through all the constraint IDs in the table by doing a little rel-magic:
nextID := catid.ConstraintID(1)
b.QueryByID(table.TableID).ForEachElementStatus(func(_ scpb.Status, _ scpb.TargetStatus, e scpb.Element) {
v, _ := screl.Schema.GetAttribute(screl.ConstraintID, e)
if id, ok := v.(catid.ConstraintID); ok && id >= nextID {
nextID = id + 1
}
})
This should allow you to remove this method entirely, which would be nice.
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.
Thanks! We have similar nextIndexID, nextColumnID method and I like having a nextConstraintID method as well (since it might be used more than once). But I do like and will change the implementation to what you suggested.
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.
edit: in fact this method is never used in this PR (but will be in the next followup PR) so I delete it for now.
f36d289
to
a3df350
Compare
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.
Getting close!
pkg/sql/sem/tree/select.go
Outdated
// ToIndexColumnDirection converts tree.Direction to catpb.IndexColumn_Direction. | ||
func (d Direction) ToIndexColumnDirection() catpb.IndexColumn_Direction { | ||
switch d { | ||
case DefaultDirection, Ascending: | ||
return catpb.IndexColumn_ASC | ||
case Descending: | ||
return catpb.IndexColumn_DESC | ||
default: | ||
panic(fmt.Sprintf("invalid direction %s", d)) | ||
} | ||
} | ||
|
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 like this dependency. Can we put this somewhere else? I would love if we could fully separate the catalog protobufs from the ast where neither know about each other. It'll take some time, but this is moving backwards. Currently tree doesn't import any of the protobufs.
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'd expect the below rule to prevent this from passing.
disallowed_prefixes = [
"pkg/sql/catalog", "pkg/sql/catalog",
], ],
} | ||
|
||
// TODO (xiang): This section contains all fall-back cases and need to | ||
// be removed to fully support `ALTER PRIMARY KEY`. |
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.
nit: bad indentation
// thus a new primary index has already been created. We'd like | ||
// to support this use case one day | ||
// (e.g. `ALTER TABLE t ADD COLUMN ..., ALTER PRIMARY KEY ...;`). | ||
// Note that such scenarios should be caught above in | ||
// `fallBackIfConcurrentSchemaChange` and an unimplemented error | ||
// should be returned, so, here we panic with an programming 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.
nit you don't need to wrap this like this, I think it's harder to read and annoying to maintain.
// `fallBackIfConcurrentSchemaChange` and an unimplemented error | ||
// should be returned, so, here we panic with an programming error. | ||
panic("programming error: new primary index has already existed.") | ||
} else { |
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.
nit, unnest this, you don't need it nested given the panic.
|
||
colCurrentStatus, _, colElem := scpb.FindColumn(colElems) | ||
if colElem == nil { | ||
panic(fmt.Sprintf("programming error: resolving column %v does not give a "+ |
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'd rather you used an errors.AssertionFailedf
error because it'll capture the stack trace. Maybe we need a helper panicf
which combines panic
and errors.AssertionFailedWithDepthf
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.
The other advantage of the error constructors is they will properly handle redaction management for arguemnts. If you don't construct an error and instead format a string, the higher levels will redact the entire message.
return columnType | ||
} | ||
|
||
func mustRetrieveIndexElement( |
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.
One day before too long I'm going to come back and rework all of this to use rel and to be efficient. So many linear lookup loops.
func dropOldPrimaryIndex(b BuildCtx, tableID catid.DescID, oldPrimaryIndexID catid.IndexID) { | ||
oldPrimaryIndexName := mustRetrievePrimaryIndexNameElem(b, tableID, oldPrimaryIndexID).Name | ||
|
||
b.ResolveIndex(tableID, tree.Name(oldPrimaryIndexName), ResolveParams{ | ||
IsExistenceOptional: false, | ||
RequiredPrivilege: privilege.CREATE, | ||
}).ForEachElementStatus(func(_ scpb.Status, target scpb.TargetStatus, e scpb.Element) { | ||
if target != scpb.ToAbsent { | ||
b.Drop(e) | ||
} | ||
}) | ||
} |
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 not handled by createNewPrimaryIndex
?
} | ||
} | ||
|
||
// STORED columns (empty) |
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.
what's this about?
if _, err := sqlDB.Exec(` | ||
SET use_declarative_schema_changer = off; | ||
ALTER TABLE t.test ALTER PRIMARY KEY USING COLUMNS (v2); | ||
SET use_declarative_schema_changer = on;`); err != nil { |
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.
move this change into the previous commit or change this to be the commit which enables the schema change. We don't want commits where tests fail. It makes bisecting things later hard.
@@ -111,7 +111,7 @@ func (desc *wrapper) GetParentSchemaID() descpb.ID { | |||
|
|||
// IndexKeysPerRow implements the TableDescriptor interface. | |||
func (desc *wrapper) IndexKeysPerRow(idx catalog.Index) int { | |||
if desc.PrimaryIndex.ID == idx.GetID() { | |||
if desc.PrimaryIndex.ID == idx.GetID() || idx.GetEncodingType() == descpb.PrimaryIndexEncoding { |
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.
move this commit to be first
7491d62
to
af18ceb
Compare
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.
@ajwerner I've addressed your comments and it's RFAL again.
Reviewable status: complete! 0 of 0 LGTMs obtained (waiting on @ajwerner and @postamar)
pkg/sql/catalog/tabledesc/structured.go
line 114 at r13 (raw file):
Previously, ajwerner wrote…
move this commit to be first
done
pkg/sql/schemachanger/scbuild/internal/scbuildstmt/alter_table_alter_primary_key.go
line 51 at r11 (raw file):
Previously, ajwerner wrote…
nit: bad indentation
done
Code quote:
// TODO (xiang): This section contains all fall-back cases and need to
// be removed to fully support `ALTER PRIMARY KEY`.
pkg/sql/schemachanger/scbuild/internal/scbuildstmt/alter_table_alter_primary_key.go
line 67 at r11 (raw file):
Previously, ajwerner wrote…
nit you don't need to wrap this like this, I think it's harder to read and annoying to maintain.
done
Code quote:
Note that such scenarios should be caught above in
pkg/sql/schemachanger/scbuild/internal/scbuildstmt/alter_table_alter_primary_key.go
line 69 at r11 (raw file):
Previously, ajwerner wrote…
nit, unnest this, you don't need it nested given the panic.
done
pkg/sql/schemachanger/scbuild/internal/scbuildstmt/alter_table_alter_primary_key.go
line 173 at r11 (raw file):
Previously, ajwerner wrote…
The other advantage of the error constructors is they will properly handle redaction management for arguemnts. If you don't construct an error and instead format a string, the higher levels will redact the entire message.
done
pkg/sql/schemachanger/scbuild/internal/scbuildstmt/alter_table_alter_primary_key.go
line 221 at r11 (raw file):
Previously, ajwerner wrote…
nit: Use capital letters to start sentences.
done
pkg/sql/schemachanger/scbuild/internal/scbuildstmt/alter_table_alter_primary_key.go
line 253 at r11 (raw file):
Previously, ajwerner wrote…
I don't think this is good enough. Consider the case where we've had a previous statement in the same transaction but all of the elements in the statement phase have moved away from their initial status. Consider just checking if the elements are not in their terminal state.
you're right. Done!
pkg/sql/schemachanger/scbuild/internal/scbuildstmt/alter_table_alter_primary_key.go
line 340 at r11 (raw file):
Previously, ajwerner wrote…
same wrapping nit
done
pkg/sql/schemachanger/scbuild/internal/scbuildstmt/alter_table_alter_primary_key.go
line 408 at r11 (raw file):
Previously, ajwerner wrote…
One day before too long I'm going to come back and rework all of this to use rel and to be efficient. So many linear lookup loops.
totally supported! Thanks in advance!
pkg/sql/schemachanger/scbuild/internal/scbuildstmt/alter_table_alter_primary_key.go
line 458 at r11 (raw file):
Previously, ajwerner wrote…
Is this not handled by
createNewPrimaryIndex
?
you're right! This function is never used bc I forgot to delete it after I refactored the code to reuse createNewPrimaryIndex
pkg/sql/schemachanger/scbuild/internal/scbuildstmt/alter_table_alter_primary_key.go
line 614 at r11 (raw file):
Previously, ajwerner wrote…
what's this about?
I just want to leave a comment there to say there is no STORED columns in this case. I've removed this line.
pkg/sql/schema_changer_test.go
line 2652 at r12 (raw file):
Previously, ajwerner wrote…
move this change into the previous commit or change this to be the commit which enables the schema change. We don't want commits where tests fail. It makes bisecting things later hard.
done. I've moved it to the last commit where I turn on ALTER PRIMARY KEY
pkg/sql/sem/tree/select.go
line 758 at r10 (raw file):
Previously, ajwerner wrote…
I'd expect the below rule to prevent this from passing.
disallowed_prefixes = [ "pkg/sql/catalog", "pkg/sql/catalog", ], ],
I've moved this utility function to be in package scbuildstmt
as one of many helpers there.
af18ceb
to
4aa512c
Compare
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.
The rttanalysis
failures are unexpected. You've got a couple more tests to fix.
Reviewed 2 of 6 files at r15, 1 of 2 files at r17.
Reviewable status: complete! 0 of 0 LGTMs obtained (waiting on @ajwerner, @postamar, and @Xiang-Gu)
pkg/sql/schemachanger/scbuild/internal/scbuildstmt/alter_table_alter_primary_key.go
line 128 at r17 (raw file):
b.EvalCtx().ClientNoticeSender.BufferClientNotice(b, pgnotice.Newf( "primary key changes are finalized asynchronously; "+
this is not true. If a test expects it, let's get rid of that test.
911b970
to
bdb3764
Compare
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've fixed the CI and address the comments. RFAL
Reviewable status: complete! 0 of 0 LGTMs obtained (waiting on @ajwerner and @postamar)
pkg/sql/schemachanger/scbuild/internal/scbuildstmt/alter_table_alter_primary_key.go
line 128 at r17 (raw file):
Previously, ajwerner wrote…
this is not true. If a test expects it, let's get rid of that test.
done
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.
Reviewed 2 of 8 files at r7, 1 of 15 files at r10, 2 of 11 files at r16, 1 of 12 files at r18, 2 of 2 files at r19, 3 of 4 files at r20, 3 of 20 files at r21, 2 of 2 files at r22.
Reviewable status: complete! 1 of 0 LGTMs obtained (waiting on @ajwerner, @postamar, and @Xiang-Gu)
pkg/sql/logictest/testdata/logic_test/alter_primary_key
line 7 at r22 (raw file):
INSERT INTO t VALUES (1, 2, 3, 4), (5, 6, 7, 8) query T noticetrace
nit: change this to statement ok
?
Code quote:
query T noticetrace
ALTER TABLE t ALTER PRIMARY KEY USING COLUMNS (y, z)
pkg/sql/schemachanger/scbuild/internal/scbuildstmt/alter_table_alter_primary_key.go
line 75 at r22 (raw file):
// Get all KEY columns from t.Columns allColumnsName2IDMapping := getAllColumnsName2IDMapping(b, tbl.TableID)
nit: I don't think the use of 2
is clearer than To
, can you rename all these?
bdb3764
to
e2328e3
Compare
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.
Reviewable status: complete! 0 of 0 LGTMs obtained (and 1 stale) (waiting on @ajwerner and @postamar)
pkg/sql/logictest/testdata/logic_test/alter_primary_key
line 7 at r22 (raw file):
Previously, ajwerner wrote…
nit: change this to
statement ok
?
done
pkg/sql/schemachanger/scbuild/internal/scbuildstmt/alter_table_alter_primary_key.go
line 75 at r22 (raw file):
Previously, ajwerner wrote…
nit: I don't think the use of
2
is clearer thanTo
, can you rename all these?
done
…or a row in an index We encounter an issue for this case ``` CREATE TABLE t (i INT PRIMARY KEY, j INT NOT NULL, FAMILY (i), FAMILY (j)); INSERT INTO t VALUES (23, 24); ALTER TABLE t ALTER PRIMARY KEY USING COLUMNS (j); ``` where the last `ALTER PRIMARY KEY` will result in duplicate entries in the new primary index, because the number of estimated keys for a row in this new primary index is incorrectly estimated to be 1, rather than 2 (the number of column families).
Previously, we issued a notice to customer for `ALTER PRIMARY KEY`, saying the altering primary key is done asynchronously and subsequent schema change might be rejected. This was no longer true (see the slace conversation https://cockroachlabs.slack.com/archives/C04U1BTF8/p1640124375172500 for some history. This PR removes this notice and modified the test that tests this notice.
The PR implements `ALTER PRIMARY KEY` under the declarative schema changer framework that handles the simplest, "vanilla" case like ``` CREATE TABLE t (i INT PRIMARY KEY, j INT NOT NULL) ALTER TABLE t ALTER PRIMARY KEY USING COLUMNS (j) ``` This is the first of a series PRs where followup PRs will expand its capabilities to be able to handle more complex cases, including 1. Allow the requested new primary key to be hash-sharded; 2. Consider the case where the old primary index is on the implicitly created `rowid` column, in which case we also need to drop that column; 3. Consider the case where altering primary key requires us to modify existing secondary indexes(see the legacy schema change about in what cases we should rewrite) 4. Consider partitioning and locality (I'm not sure what they are, and why they play a role when `ALTER PRIMARY KEY` but I've seen them in the old schema changer, so I assume we ought to do something about them too here). Release note: None
Release note: None
A few tests failed because they test/reply on specific behavior in the old schema changer, so we disabled them in this pr.
e2328e3
to
8a25332
Compare
bors r+ |
Build failed (retrying...): |
Build failed (retrying...): |
Build failed: |
The merge failed due to a bunch of flakes, which ought to be fixed in the current bors batch. Retrying. bors r+ |
Build succeeded: |
The PR implements
ALTER PRIMARY KEY
under the declarative schemachanger framework that handles the simplest, "vanilla" case like
This is the first of a series PRs where followup PRs will expand its
capabilities to be able to handle more complex cases, including
modify existing secondary indexes(see the legacy schema change
about in what cases we should rewrite)
created
rowid
column, in which case we also need to drop thatcolumn;
and why they play a role when
ALTER PRIMARY KEY
but I've seenthem in the old schema changer, so I assume we ought to do
something about them too here).
ALTER PRIMARY KEY
with concurrent schema changestatements. E.g.
ALTER TABLE t ADD COLUMN k INT NOT NULL DEFAULT 30, ALTER PRIMARY KEY USING COLUMNS (j);
related: #83932
Release note: None