Skip to content

Commit 5a4e4e8

Browse files
craig[bot]rafisskyle-a-wongmsbutlermw5h
committed
149444: schemachanger: implement ALTER COLUMN [SET | DROP] ON UPDATE in declarative r=rafiss a=rafiss This adds support for setting and dropping ON UPDATE expressions to the declarative schema changer. No new elements were needed, so this was pretty straightforward. fixes #139604 Release note: None 149838: ui: fix bug where "Drop Unused Index" recommendations are not populat… r=kyle-a-wong a=kyle-a-wong …ed on Schema Insights When hard refreshing on the Schema Index tab of the insights page, "Drop Unused Index" recommendations don't populate. This is happening due to a race condition in db console, where db console needs cluster settings from the redux store to query for unused indexes. On a hard refresh, the cluster settings aren't in the redux store when querying for these indexes, so it uses the default cluster setting. To fix, the query no longer depends on cluster settings from the reduxstore. Instead, thequery joins on crdb_internal.cluster_settings. Epic: CC-30965 Fixes: CC-31265 Release note (ui change): Fix bug where "Drop Unused Index" recommendations are not populated on the schema index page. 150142: restore: delete comments after failed or cancelled cluster restore r=dt a=msbutler This patch ensures that after a failed or canceled cluster restore, comments from dropped descriptors are removed. Informs #149453 Release note: none 150154: gceworker.sh: update default worker image r=mw5h a=mw5h Ubuntu 20.04 LTS is past EOL and no longer available. DevInf has made 20.04 available in the cockroach-workers project as 'crl-ubuntu-2004'. We also no longer suppoert image families, so this patch changes the image project to 'cockroach-workers' and points at the new image. Epic: none Release note: None Co-authored-by: Rafi Shamim <[email protected]> Co-authored-by: Kyle Wong <[email protected]> Co-authored-by: Michael Butler <[email protected]> Co-authored-by: Matt White <[email protected]>
5 parents 7d97799 + 0094d6a + f7af5dc + 26bee83 + 7e4e7fe commit 5a4e4e8

File tree

34 files changed

+1253
-20
lines changed

34 files changed

+1253
-20
lines changed

pkg/backup/backup_test.go

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11184,3 +11184,60 @@ CREATE TABLE child_pk (k INT8 PRIMARY KEY REFERENCES parent);
1118411184
sqlDB.Exec(t, `DROP DATABASE test`)
1118511185
}
1118611186
}
11187+
11188+
func TestRestoreFailureDeletesComments(t *testing.T) {
11189+
defer leaktest.AfterTest(t)()
11190+
defer log.Scope(t).Close(t)
11191+
11192+
_, sqlDB, cleanupFn := backupRestoreTestSetupEmpty(t, singleNode, "", InitManualReplication, base.TestClusterArgs{})
11193+
defer cleanupFn()
11194+
11195+
// Set pause point for after the system tables have been published.
11196+
sqlDB.Exec(t, `SET CLUSTER SETTING jobs.debug.pausepoints = 'restore.after_cleanup_temp_system_tables'`)
11197+
11198+
commentCountQuery := `SELECT count(*) FROM system.comments`
11199+
11200+
var count int
11201+
sqlDB.QueryRow(t, commentCountQuery).Scan(&count)
11202+
require.Equal(t, 0, count)
11203+
11204+
// Create a database with tables, types, and schemas that have comments
11205+
sqlDB.Exec(t, `CREATE DATABASE test_db`)
11206+
sqlDB.Exec(t, `USE test_db`)
11207+
11208+
sqlDB.Exec(t, `CREATE TYPE custom_type AS ENUM ('val1', 'val2')`)
11209+
sqlDB.Exec(t, `COMMENT ON TYPE custom_type IS 'This is a custom type comment'`)
11210+
11211+
sqlDB.Exec(t, `CREATE SCHEMA test_schema`)
11212+
sqlDB.Exec(t, `COMMENT ON SCHEMA test_schema IS 'This is a schema comment'`)
11213+
11214+
sqlDB.Exec(t, `CREATE TABLE test_schema.test_table (id INT PRIMARY KEY, name STRING)`)
11215+
sqlDB.Exec(t, `COMMENT ON TABLE test_schema.test_table IS 'This is a table comment'`)
11216+
11217+
sqlDB.Exec(t, `COMMENT ON DATABASE test_db IS 'This is a database comment'`)
11218+
11219+
sqlDB.QueryRow(t, commentCountQuery).Scan(&count)
11220+
require.Equal(t, 4, count)
11221+
11222+
sqlDB.Exec(t, `BACKUP INTO 'nodelocal://1/test_backup'`)
11223+
11224+
sqlDB.Exec(t, `USE system`)
11225+
11226+
sqlDB.Exec(t, `DROP DATABASE test_db CASCADE`)
11227+
sqlDB.QueryRow(t, commentCountQuery).Scan(&count)
11228+
require.Equal(t, 0, count)
11229+
11230+
var jobID jobspb.JobID
11231+
sqlDB.QueryRow(t, `RESTORE FROM LATEST IN 'nodelocal://1/test_backup' WITH detached`).Scan(&jobID)
11232+
jobutils.WaitForJobToPause(t, sqlDB, jobID)
11233+
11234+
sqlDB.QueryRow(t, commentCountQuery).Scan(&count)
11235+
require.Equal(t, 4, count)
11236+
11237+
// Cancel the restore job
11238+
sqlDB.Exec(t, `CANCEL JOB $1`, jobID)
11239+
jobutils.WaitForJobToCancel(t, sqlDB, jobID)
11240+
11241+
sqlDB.QueryRow(t, commentCountQuery).Scan(&count)
11242+
require.Equal(t, 0, count)
11243+
}

pkg/backup/restore_job.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ import (
3737
"github.com/cockroachdb/cockroach/pkg/settings/cluster"
3838
"github.com/cockroachdb/cockroach/pkg/sql"
3939
"github.com/cockroachdb/cockroach/pkg/sql/catalog"
40+
"github.com/cockroachdb/cockroach/pkg/sql/catalog/catalogkeys"
4041
"github.com/cockroachdb/cockroach/pkg/sql/catalog/catpb"
4142
"github.com/cockroachdb/cockroach/pkg/sql/catalog/dbdesc"
4243
"github.com/cockroachdb/cockroach/pkg/sql/catalog/descidgen"
@@ -2843,6 +2844,10 @@ func (r *restoreResumer) dropDescriptors(
28432844
tablesToGC = append(tablesToGC, tableToDrop.ID)
28442845
tableToDrop.SetDropped()
28452846

2847+
if err := descsCol.DeleteTableComments(ctx, kvTrace, b, tableToDrop.ID); err != nil {
2848+
return err
2849+
}
2850+
28462851
// Drop any schedules we may have implicitly created.
28472852
if tableToDrop.HasRowLevelTTL() {
28482853
scheduleID := tableToDrop.RowLevelTTL.ScheduleID
@@ -2898,6 +2903,14 @@ func (r *restoreResumer) dropDescriptors(
28982903
}
28992904
mutType.SetDropped()
29002905

2906+
if err := descsCol.DeleteCommentInBatch(
2907+
ctx,
2908+
kvTrace,
2909+
b,
2910+
catalogkeys.MakeCommentKey(uint32(typDesc.ID), 0, catalogkeys.TypeCommentType)); err != nil {
2911+
return err
2912+
}
2913+
29012914
if err := descsCol.DeleteNamespaceEntryToBatch(ctx, kvTrace, typDesc, b); err != nil {
29022915
return err
29032916
}
@@ -2993,6 +3006,14 @@ func (r *restoreResumer) dropDescriptors(
29933006
entry.db = mutParent.(*dbdesc.Mutable)
29943007
}
29953008

3009+
if err := descsCol.DeleteCommentInBatch(
3010+
ctx,
3011+
kvTrace,
3012+
b,
3013+
catalogkeys.MakeCommentKey(uint32(schemaDesc.GetID()), 0, catalogkeys.SchemaCommentType)); err != nil {
3014+
return err
3015+
}
3016+
29963017
// Delete schema entries in descriptor and namespace system tables.
29973018
if err := descsCol.DeleteNamespaceEntryToBatch(ctx, kvTrace, mutSchema, b); err != nil {
29983019
return err
@@ -3076,6 +3097,14 @@ func (r *restoreResumer) dropDescriptors(
30763097
return err
30773098
}
30783099
}
3100+
if err := descsCol.DeleteCommentInBatch(
3101+
ctx,
3102+
kvTrace,
3103+
b,
3104+
catalogkeys.MakeCommentKey(uint32(dbDesc.GetID()), 0, catalogkeys.DatabaseCommentType)); err != nil {
3105+
return err
3106+
}
3107+
30793108
if err := descsCol.DeleteNamespaceEntryToBatch(ctx, kvTrace, db, b); err != nil {
30803109
return err
30813110
}

pkg/ccl/schemachangerccl/sctestbackupccl/backup_base_generated_test.go

Lines changed: 56 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/sql/alter_table.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1000,10 +1000,9 @@ func applyColumnMutation(
10001000
fk.OnUpdate != semenumpb.ForeignKeyAction_RESTRICT {
10011001
return pgerror.Newf(
10021002
pgcode.InvalidColumnDefinition,
1003-
"column %s(%d) cannot have both an ON UPDATE expression and a foreign"+
1004-
" key ON UPDATE action",
1003+
"column cannot specify both ON UPDATE expression and a foreign"+
1004+
" key ON UPDATE action for column %q",
10051005
col.GetName(),
1006-
col.GetID(),
10071006
)
10081007
}
10091008
}

pkg/sql/catalog/rewrite/rewrite.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1010,6 +1010,11 @@ func rewriteSchemaChangerState(
10101010
// just drop the target.
10111011
removeElementAtCurrentIdx()
10121012
continue
1013+
case *scpb.ColumnOnUpdateExpression:
1014+
// IF there is any dependency missing for column ON UPDATE expression,
1015+
// we just drop the target.
1016+
removeElementAtCurrentIdx()
1017+
continue
10131018
case *scpb.SequenceOwner:
10141019
// If a sequence owner is missing the sequence, then the sequence
10151020
// was already dropped and this element can be safely removed.

pkg/sql/logictest/testdata/logic_test/on_update

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ CREATE TABLE test_fk_invalid (p STRING PRIMARY KEY, j STRING ON UPDATE 'test', C
167167
statement ok
168168
CREATE TABLE alter_fk (p STRING PRIMARY KEY, j STRING REFERENCES test_fk_base (j) ON UPDATE CASCADE)
169169

170-
statement error pq: column j\(2\) cannot have both an ON UPDATE expression and a foreign key ON UPDATE action
170+
statement error cannot specify both ON UPDATE expression and a foreign key ON UPDATE action for column "j"
171171
ALTER TABLE alter_fk ALTER COLUMN j SET ON UPDATE 'failure'
172172

173173
statement ok

pkg/sql/schemachanger/scbuild/internal/scbuildstmt/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ go_library(
1010
"alter_table_alter_column_drop_not_null.go",
1111
"alter_table_alter_column_set_default.go",
1212
"alter_table_alter_column_set_not_null.go",
13+
"alter_table_alter_column_set_on_update.go",
1314
"alter_table_alter_column_type.go",
1415
"alter_table_alter_primary_key.go",
1516
"alter_table_drop_column.go",

pkg/sql/schemachanger/scbuild/internal/scbuildstmt/alter_table.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ var supportedAlterTableStatements = map[reflect.Type]supportedAlterTableCommand{
3838
reflect.TypeOf((*tree.AlterTableDropConstraint)(nil)): {fn: alterTableDropConstraint, on: true, checks: nil},
3939
reflect.TypeOf((*tree.AlterTableValidateConstraint)(nil)): {fn: alterTableValidateConstraint, on: true, checks: nil},
4040
reflect.TypeOf((*tree.AlterTableSetDefault)(nil)): {fn: alterTableSetDefault, on: true, checks: nil},
41+
reflect.TypeOf((*tree.AlterTableSetOnUpdate)(nil)): {fn: alterTableSetOnUpdate, on: true, checks: isV254Active},
4142
reflect.TypeOf((*tree.AlterTableAlterColumnType)(nil)): {fn: alterTableAlterColumnType, on: true, checks: nil},
4243
reflect.TypeOf((*tree.AlterTableSetRLSMode)(nil)): {fn: alterTableSetRLSMode, on: true, checks: isV252Active},
4344
reflect.TypeOf((*tree.AlterTableDropNotNull)(nil)): {fn: alterTableDropNotNull, on: true, checks: isV253Active},

pkg/sql/schemachanger/scbuild/internal/scbuildstmt/alter_table_alter_column_set_default.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ func panicIfInvalidNonComputedColumnExpr(
8080
}
8181

8282
colType := mustRetrieveColumnTypeElem(b, tbl.TableID, col.ColumnID)
83-
typedNewExpr, _, err := sanitizeColumnExpression(context.Background(), b.SemaCtx(), newExpr, colType, schemaChange)
83+
typedNewExpr, _, err := sanitizeColumnExpression(b, b.SemaCtx(), newExpr, colType, schemaChange)
8484
if err != nil {
8585
panic(err)
8686
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
// Copyright 2025 The Cockroach Authors.
2+
//
3+
// Use of this software is governed by the CockroachDB Software License
4+
// included in the /LICENSE file.
5+
6+
package scbuildstmt
7+
8+
import (
9+
"github.com/cockroachdb/cockroach/pkg/sql/schemachanger/scpb"
10+
"github.com/cockroachdb/cockroach/pkg/sql/sem/tree"
11+
)
12+
13+
func alterTableSetOnUpdate(
14+
b BuildCtx,
15+
tn *tree.TableName,
16+
tbl *scpb.Table,
17+
stmt tree.Statement,
18+
t *tree.AlterTableSetOnUpdate,
19+
) {
20+
alterColumnPreChecks(b, tn, tbl, t.Column)
21+
colID := getColumnIDFromColumnName(b, tbl.TableID, t.Column, true /* required */)
22+
col := mustRetrieveColumnElem(b, tbl.TableID, colID)
23+
oldOnUpdateExpr := retrieveColumnOnUpdateExpressionElem(b, tbl.TableID, colID)
24+
colType := mustRetrieveColumnTypeElem(b, tbl.TableID, colID)
25+
26+
// Block alters on system columns.
27+
panicIfSystemColumn(col, t.Column.String())
28+
29+
// Block disallowed operations on computed columns.
30+
panicIfComputedColumn(b, tn.ObjectName, colType, t.Column.String(), t.Expr)
31+
32+
// For DROP ON UPDATE.
33+
if t.Expr == nil {
34+
if oldOnUpdateExpr != nil {
35+
b.Drop(oldOnUpdateExpr)
36+
}
37+
return
38+
}
39+
40+
// If our target column already has an ON UPDATE expression, we want to drop it first.
41+
if oldOnUpdateExpr != nil {
42+
b.Drop(oldOnUpdateExpr)
43+
}
44+
typedExpr := panicIfInvalidNonComputedColumnExpr(b, tbl, tn.ToUnresolvedObjectName(), col, t.Column.String(), t.Expr, tree.ColumnOnUpdateExpr)
45+
46+
b.Add(&scpb.ColumnOnUpdateExpression{
47+
TableID: tbl.TableID,
48+
ColumnID: colID,
49+
Expression: *b.WrapExpression(tbl.TableID, typedExpr),
50+
})
51+
}

0 commit comments

Comments
 (0)