-
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: validate check constraints with the schema changer #34301
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.
Reviewable status: complete! 0 of 0 LGTMs obtained (waiting on @dt, @lucy-zhang, and @vivekmenezes)
pkg/sql/alter_table.go, line 217 at r1 (raw file):
// A previous command could have added a column which the new constraint uses, // allocate IDs now. if err != n.tableDesc.AllocateIDs() {
This seems out of place. Does something break without it?
pkg/sql/backfill.go, line 601 at r1 (raw file):
return err } doneCheckValidation = true
What if there are two columns with two check constraints?
pkg/sql/backfill.go, line 624 at r1 (raw file):
case *sqlbase.DescriptorMutation_Constraint: return errors.Errorf("constraint validation mutation cannot be in the DROP state within the same transaction: %+v", m)
How about BEGIN; ALTER ADD COLUMN a INT CHECK a < 1; ALTER DROP COLUMN a; COMMIT ?
pkg/sql/create_table.go, line 1488 at r1 (raw file):
col, dropped, err := desc.FindColumnByName(c.ColumnName) if err != nil || dropped {
Why do you need this change?
pkg/sql/schema_changer.go, line 1160 at r1 (raw file):
} } }
Do you think you can add this logic to sc.deleteIndexMutationsWithReversedColumns() and rename that to sc.DeleteDependentMutationsWithReversedColumns() ?
pkg/sql/schema_changer.go, line 1838 at r1 (raw file):
Location: dummyLocation, }, User: security.NodeUser,
I don't believe you need this because you are using the backfiller and not the internal executor
pkg/sql/backfill/backfill.go, line 84 at r1 (raw file):
cb.evalCtx = evalCtx numCols := len(desc.Columns) cb.cols = desc.Columns
Does desc.WritableColumns() work here?
pkg/sql/distsqlrun/checkbackfiller.go, line 28 at r1 (raw file):
) // indexBackfiller is a processor that backfills new indexes.
checkBackfiller
pkg/sql/sqlbase/structured.go, line 252 at r1 (raw file):
} checks := make([]TableDescriptor_CheckConstraint, len(tbl.Checks))
desc.allChecks =
pkg/sql/sqlbase/structured.go, line 2075 at r1 (raw file):
} } return nil, fmt.Errorf("index %q does not exist", name)
check %q does not exist.
pkg/sql/sqlbase/structured.proto, line 194 at r1 (raw file):
enum ConstraintValidity { Validated = 0;
Can you add a comment for Validated as well:
// The constraint is valid across all rows.
pkg/sql/sqlbase/structured.proto, line 196 at r1 (raw file):
Validated = 0; Unvalidated = 1; // The state for a constraint that was just added, but whose validation
Perhaps add: // The constraint has yet to be checked across all rows.
pkg/sql/sqlbase/structured.proto, line 501 at r1 (raw file):
// containing each column/index descriptor being added or dropped. message DescriptorMutation { message ConstraintToValidate {
let's place this message outside of DescriptorMutation like the other messages.
938fb99
to
5b9aac0
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 @dt and @vivekmenezes)
pkg/sql/alter_table.go, line 217 at r1 (raw file):
Previously, vivekmenezes wrote…
This seems out of place. Does something break without it?
Yeah, if you add a check constraint on a column that's being added, the check will contain a column ID of 0 in its ColumnIDs
field which will never get updated later. The test that fails is TestSchemaChangeAfterCreateInTxn
, at the SCRUB check.
To make sure it wasn't just a SCRUB false positive, I added an UPDATE statement to it, which returns an error when it can't find column 0. (For some reason, INSERT still works even with the invalid column id.)
pkg/sql/backfill.go, line 601 at r1 (raw file):
Previously, vivekmenezes wrote…
What if there are two columns with two check constraints?
The backfiller validates every check constraint at once. I updated the comment to make this more clear.
pkg/sql/backfill.go, line 624 at r1 (raw file):
Previously, vivekmenezes wrote…
How about BEGIN; ALTER ADD COLUMN a INT CHECK a < 1; ALTER DROP COLUMN a; COMMIT ?
If you do that, you'll get the constraint "a" in the middle of being added
error.
This method only gets called when there's a schema change for a new table added earlier in the same transaction. We never add a DROP mutation when dropping a check, we just remove it from the list of checks. So the only time any check validation mutation can be in the DROP state is if it's getting rolled back because of an error, which is a different situation from what this method covers.
pkg/sql/create_table.go, line 1488 at r1 (raw file):
Previously, vivekmenezes wrote…
Why do you need this change?
The method gets called by MakeCheckConstraint
. This change is to deal with non-public columns currently being added.
pkg/sql/schema_changer.go, line 1160 at r1 (raw file):
Previously, vivekmenezes wrote…
Do you think you can add this logic to sc.deleteIndexMutationsWithReversedColumns() and rename that to sc.DeleteDependentMutationsWithReversedColumns() ?
I'm not sure about adding it to that function or any existing function, since this is a new kind of behavior (we're removing something from the table descriptor itself, not just the mutations). I split this out into a new function.
pkg/sql/schema_changer.go, line 1838 at r1 (raw file):
Previously, vivekmenezes wrote…
I don't believe you need this because you are using the backfiller and not the internal executor
You're right (I forgot to remove this when I added the backfiller)
pkg/sql/backfill/backfill.go, line 84 at r1 (raw file):
Previously, vivekmenezes wrote…
Does desc.WritableColumns() work here?
I don't think so, since we also want to exclude columns being dropped
pkg/sql/distsqlrun/checkbackfiller.go, line 28 at r1 (raw file):
Previously, vivekmenezes wrote…
checkBackfiller
Done.
pkg/sql/sqlbase/structured.go, line 252 at r1 (raw file):
Previously, vivekmenezes wrote…
desc.allChecks =
Done.
pkg/sql/sqlbase/structured.go, line 2075 at r1 (raw file):
Previously, vivekmenezes wrote…
check %q does not exist.
Done.
pkg/sql/sqlbase/structured.proto, line 194 at r1 (raw file):
Previously, vivekmenezes wrote…
Can you add a comment for Validated as well:
// The constraint is valid across all rows.
Done.
pkg/sql/sqlbase/structured.proto, line 196 at r1 (raw file):
Previously, vivekmenezes wrote…
Perhaps add: // The constraint has yet to be checked across all rows.
Done.
pkg/sql/sqlbase/structured.proto, line 501 at r1 (raw file):
Previously, vivekmenezes wrote…
let's place this message outside of DescriptorMutation like the other messages.
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.
Ready for another look.
I also added a few tests to the schema_change_in_txn
logic test for the errors that are returned when trying to drop or validate a check constraint that's being added.
Reviewable status: complete! 0 of 0 LGTMs obtained (waiting on @dt and @vivekmenezes)
5803e2c
to
ad55922
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.
Thanks for updating the PR. I think this PR should wait on #34263 to merge so you can remove the backfill functionality in this PR. Thanks
Reviewable status: complete! 0 of 0 LGTMs obtained (waiting on @dt and @vivekmenezes)
3580075
to
cea639a
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.
This is ready for another look. I replaced the backfiller with the InternalExecutor SQL query, and added some more tests, mostly for when a table is created and schema changes are made in the same transaction, since that case currently has very little coverage.
Reviewable status: complete! 0 of 0 LGTMs obtained (waiting on @dt and @vivekmenezes)
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 @dt and @lucy-zhang)
pkg/sql/backfill.go, line 284 at r2 (raw file):
} return validateCheckExpr(ctx, check.Expr, desc.TableDesc(), ie, txn)
All the code above is a copy of the code in ValidateCheckInTxn() . Make the recommended change to ValidateCheckInTxn and call it from here too.
pkg/sql/backfill.go, line 898 at r2 (raw file):
tableDesc *MutableTableDescriptor, txn *client.Txn, checks []sqlbase.ConstraintToValidate,
You can iterate on the checks outside this function and then you will be able to use ValidateCheckInTxn() both here and in the normal case above. See my other comment.
pkg/sql/check.go, line 54 at r2 (raw file):
queryStr := tree.AsStringWithFlags(stmt, tree.FmtParsable) log.Infof(ctx, "Validating check constraint %q with query %q", expr.String(), queryStr)
take out
pkg/sql/sqlbase/structured.go, line 2291 at r2 (raw file):
i++ } table.Mutations = table.Mutations[i:]
good catch
Nice work! |
cea639a
to
b6a1faa
Compare
Currently, constraints are added in the `Unvalidated` state, and are not validated for existing rows until ALTER TABLE ... VALIDATE CONSTRAINT is run. With this change, check constraints will be validated asynchronously after they are added by default (and similar changes to FKs are to follow). This addresses the problematic long-running transactions caused by the current implementation of VALIDATE CONSTRAINT. This PR is a rework of cockroachdb#32504, and has the same tests. With this change, check constraints will be added to the table descriptor in the new `Validating` state, visible to CRUD operations, and a mutation is queued indicating that the constraint is to be validated. During the backfill step, the constraint is validated for existing rows. If validation succeeds, then the constraint moves to the `Validated` state; otherwise, it is dropped. The behavior when dropping constraints (either via DROP CONSTRAINT or indirectly when a column is dropped) is unchanged: no mutation is enqueued. As part of this change, check constraints can be added to non-public columns in the process of being added, including columns that were created earlier in the same transaction. The main difference between this PR and cockroachdb#32504 is that cockroachdb#32504 does not add the constraint to the table descriptor until it has been validated. Release note (sql change): Check constraint adds by default will validate table data with the added constraint asynchronously after the transaction commits.
b6a1faa
to
baa598c
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.
TFTR, just 1 minor question
Reviewable status: complete! 0 of 0 LGTMs obtained (waiting on @dt, @lucy-zhang, and @vivekmenezes)
pkg/sql/backfill.go, line 284 at r2 (raw file):
Previously, vivekmenezes wrote…
All the code above is a copy of the code in ValidateCheckInTxn() . Make the recommended change to ValidateCheckInTxn and call it from here too.
Done.
pkg/sql/backfill.go, line 898 at r2 (raw file):
Previously, vivekmenezes wrote…
You can iterate on the checks outside this function and then you will be able to use ValidateCheckInTxn() both here and in the normal case above. See my other comment.
Done.
pkg/sql/check.go, line 54 at r2 (raw file):
Previously, vivekmenezes wrote…
take out
I added this to match the logging for the FK validation queries (elsewhere in this file). Should the logging be removed?
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! 1 of 0 LGTMs obtained (waiting on @dt and @lucy-zhang)
bors r+ |
Build failed (retrying...) |
Build failed |
I'm getting |
bors r+ |
34301: sql: validate check constraints with the schema changer r=lucy-zhang a=lucy-zhang Currently, constraints are added in the `Unvalidated` state, and are not validated for existing rows until ALTER TABLE ... VALIDATE CONSTRAINT is run. With this change, check constraints will be validated asynchronously after they are added by default (and similar changes to FKs are to follow). This addresses the problematic long-running transactions caused by the current implementation of VALIDATE CONSTRAINT. This PR is a rework of #32504 and has the same tests. With this change, check constraints will be added to the table descriptor in the new `Validating` state, visible to CRUD operations, and a mutation is queued indicating that the constraint is to be validated. During the backfill step, the constraint is validated for existing rows. If validation succeeds, then the constraint moves to the `Validated` state; otherwise, it is dropped. The behavior when dropping constraints (either via DROP CONSTRAINT or indirectly when a column is dropped) is unchanged: no mutation is enqueued. As part of this change, check constraints can be added to non-public columns in the process of being added, including columns that were created earlier in the same transaction. The main difference between this PR and #32504 is that #32504 does not add the constraint to the table descriptor until it has been validated. See #34238 for more context. Release note (sql change): Check constraint adds by default will validate table data with the added constraint asynchronously after the transaction commits. 34720: rpc: always trace incoming RPCs if tracing is enabled r=andreimatei a=andreimatei Before this patch, an incoming RPC would not be traced if the caller wasn't traced. Usually this was inconsequential, as the caller is generally traced if tracing is enabled in various ways. However, for the status server (AdminUI calls) this was not true - the caller (the browser, through a HTTP->gRPC gateway) was never tracing a call. This patch makes the server create a span regardless of the caller if tracing is enabled. Fixes #34310 Release note: None 34798: roachtest: add two more indexes to bulk index creation test r=vivekmenezes a=vivekmenezes Release note: None 34829: jobs: only include running and very recently finished jobs in SHOW JOBS r=dt a=dt On a cluster that has been running for a long time or with frequent periodic jobs, SHOW JOBS can output an unbounded, massive wall of text. This makes it hard to find the jobs you are likely interested in -- those that are running or have very recently finished. This changes SHOW JOBS to only include running jobs or those that finished in the last 12h. The full listing of jobs is still available via crdb_internal.jobs. Release note (general change): SHOW JOBS only returns running and recently finished jobs. Older jobs can still be inspected via the crdb_internal.jobs table. Co-authored-by: Lucy Zhang <[email protected]> Co-authored-by: Andrei Matei <[email protected]> Co-authored-by: Vivek Menezes <[email protected]> Co-authored-by: David Taylor <[email protected]>
Build succeeded |
Currently, constraints are added in the
Unvalidated
state, and are notvalidated for existing rows until ALTER TABLE ... VALIDATE CONSTRAINT is run.
With this change, check constraints will be validated asynchronously after they
are added by default (and similar changes to FKs are to follow). This addresses
the problematic long-running transactions caused by the current implementation
of VALIDATE CONSTRAINT. This PR is a rework of #32504 and has the same tests.
With this change, check constraints will be added to the table descriptor in
the new
Validating
state, visible to CRUD operations, and a mutation isqueued indicating that the constraint is to be validated. During the backfill
step, the constraint is validated for existing rows. If validation succeeds,
then the constraint moves to the
Validated
state; otherwise, it is dropped.The behavior when dropping constraints (either via DROP CONSTRAINT or
indirectly when a column is dropped) is unchanged: no mutation is enqueued.
As part of this change, check constraints can be added to non-public columns in
the process of being added, including columns that were created earlier in the
same transaction.
The main difference between this PR and #32504 is that #32504 does not add the
constraint to the table descriptor until it has been validated.
See #34238 for more context.
Release note (sql change): Check constraint adds by default will validate table
data with the added constraint asynchronously after the transaction commits.