github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/sem/tree/alter_table.go (about) 1 // Copyright 2015 The Cockroach Authors. 2 // 3 // Use of this software is governed by the Business Source License 4 // included in the file licenses/BSL.txt. 5 // 6 // As of the Change Date specified in that file, in accordance with 7 // the Business Source License, use of this software will be governed 8 // by the Apache License, Version 2.0, included in the file 9 // licenses/APL.txt. 10 11 package tree 12 13 import ( 14 "strings" 15 16 "github.com/cockroachdb/cockroach/pkg/server/telemetry" 17 "github.com/cockroachdb/cockroach/pkg/sql/sqltelemetry" 18 ) 19 20 // AlterTable represents an ALTER TABLE statement. 21 type AlterTable struct { 22 IfExists bool 23 Table *UnresolvedObjectName 24 Cmds AlterTableCmds 25 } 26 27 // Format implements the NodeFormatter interface. 28 func (node *AlterTable) Format(ctx *FmtCtx) { 29 ctx.WriteString("ALTER TABLE ") 30 if node.IfExists { 31 ctx.WriteString("IF EXISTS ") 32 } 33 ctx.FormatNode(node.Table) 34 ctx.FormatNode(&node.Cmds) 35 } 36 37 // AlterTableCmds represents a list of table alterations. 38 type AlterTableCmds []AlterTableCmd 39 40 // Format implements the NodeFormatter interface. 41 func (node *AlterTableCmds) Format(ctx *FmtCtx) { 42 for i, n := range *node { 43 if i > 0 { 44 ctx.WriteString(",") 45 } 46 ctx.FormatNode(n) 47 } 48 } 49 50 // AlterTableCmd represents a table modification operation. 51 type AlterTableCmd interface { 52 NodeFormatter 53 // TelemetryCounter returns the telemetry counter to increment 54 // when this command is used. 55 TelemetryCounter() telemetry.Counter 56 // Placeholder function to ensure that only desired types 57 // (AlterTable*) conform to the AlterTableCmd interface. 58 alterTableCmd() 59 } 60 61 func (*AlterTableAddColumn) alterTableCmd() {} 62 func (*AlterTableAddConstraint) alterTableCmd() {} 63 func (*AlterTableAlterColumnType) alterTableCmd() {} 64 func (*AlterTableAlterPrimaryKey) alterTableCmd() {} 65 func (*AlterTableDropColumn) alterTableCmd() {} 66 func (*AlterTableDropConstraint) alterTableCmd() {} 67 func (*AlterTableDropNotNull) alterTableCmd() {} 68 func (*AlterTableDropStored) alterTableCmd() {} 69 func (*AlterTableSetNotNull) alterTableCmd() {} 70 func (*AlterTableRenameColumn) alterTableCmd() {} 71 func (*AlterTableRenameConstraint) alterTableCmd() {} 72 func (*AlterTableSetAudit) alterTableCmd() {} 73 func (*AlterTableSetDefault) alterTableCmd() {} 74 func (*AlterTableValidateConstraint) alterTableCmd() {} 75 func (*AlterTablePartitionBy) alterTableCmd() {} 76 func (*AlterTableInjectStats) alterTableCmd() {} 77 78 var _ AlterTableCmd = &AlterTableAddColumn{} 79 var _ AlterTableCmd = &AlterTableAddConstraint{} 80 var _ AlterTableCmd = &AlterTableAlterColumnType{} 81 var _ AlterTableCmd = &AlterTableDropColumn{} 82 var _ AlterTableCmd = &AlterTableDropConstraint{} 83 var _ AlterTableCmd = &AlterTableDropNotNull{} 84 var _ AlterTableCmd = &AlterTableDropStored{} 85 var _ AlterTableCmd = &AlterTableSetNotNull{} 86 var _ AlterTableCmd = &AlterTableRenameColumn{} 87 var _ AlterTableCmd = &AlterTableRenameConstraint{} 88 var _ AlterTableCmd = &AlterTableSetAudit{} 89 var _ AlterTableCmd = &AlterTableSetDefault{} 90 var _ AlterTableCmd = &AlterTableValidateConstraint{} 91 var _ AlterTableCmd = &AlterTablePartitionBy{} 92 var _ AlterTableCmd = &AlterTableInjectStats{} 93 94 // ColumnMutationCmd is the subset of AlterTableCmds that modify an 95 // existing column. 96 type ColumnMutationCmd interface { 97 AlterTableCmd 98 GetColumn() Name 99 } 100 101 // AlterTableAddColumn represents an ADD COLUMN command. 102 type AlterTableAddColumn struct { 103 IfNotExists bool 104 ColumnDef *ColumnTableDef 105 } 106 107 // TelemetryCounter implements the AlterTableCmd interface. 108 func (node *AlterTableAddColumn) TelemetryCounter() telemetry.Counter { 109 return sqltelemetry.SchemaChangeAlterCounterWithExtra("table", "add_column") 110 } 111 112 // Format implements the NodeFormatter interface. 113 func (node *AlterTableAddColumn) Format(ctx *FmtCtx) { 114 ctx.WriteString(" ADD COLUMN ") 115 if node.IfNotExists { 116 ctx.WriteString("IF NOT EXISTS ") 117 } 118 ctx.FormatNode(node.ColumnDef) 119 } 120 121 // HoistAddColumnConstraints converts column constraints in ADD COLUMN commands, 122 // stored in node.Cmds, into top-level commands to add those constraints. 123 // Currently, this only applies to checks. For example, the ADD COLUMN in 124 // 125 // ALTER TABLE t ADD COLUMN a INT CHECK (a < 1) 126 // 127 // is transformed into two commands, as in 128 // 129 // ALTER TABLE t ADD COLUMN a INT, ADD CONSTRAINT check_a CHECK (a < 1) 130 // 131 // (with an auto-generated name). 132 // 133 // Note that some SQL databases require that a constraint attached to a column 134 // to refer only to the column it is attached to. We follow Postgres' behavior, 135 // however, in omitting this restriction by blindly hoisting all column 136 // constraints. For example, the following statement is accepted in 137 // CockroachDB and Postgres, but not necessarily other SQL databases: 138 // 139 // ALTER TABLE t ADD COLUMN a INT CHECK (a < b) 140 // 141 func (node *AlterTable) HoistAddColumnConstraints() { 142 var normalizedCmds AlterTableCmds 143 144 for _, cmd := range node.Cmds { 145 normalizedCmds = append(normalizedCmds, cmd) 146 147 if t, ok := cmd.(*AlterTableAddColumn); ok { 148 d := t.ColumnDef 149 for _, checkExpr := range d.CheckExprs { 150 normalizedCmds = append(normalizedCmds, 151 &AlterTableAddConstraint{ 152 ConstraintDef: &CheckConstraintTableDef{ 153 Expr: checkExpr.Expr, 154 Name: checkExpr.ConstraintName, 155 }, 156 ValidationBehavior: ValidationDefault, 157 }, 158 ) 159 } 160 d.CheckExprs = nil 161 if d.HasFKConstraint() { 162 var targetCol NameList 163 if d.References.Col != "" { 164 targetCol = append(targetCol, d.References.Col) 165 } 166 fk := &ForeignKeyConstraintTableDef{ 167 Table: *d.References.Table, 168 FromCols: NameList{d.Name}, 169 ToCols: targetCol, 170 Name: d.References.ConstraintName, 171 Actions: d.References.Actions, 172 Match: d.References.Match, 173 } 174 constraint := &AlterTableAddConstraint{ 175 ConstraintDef: fk, 176 ValidationBehavior: ValidationDefault, 177 } 178 normalizedCmds = append(normalizedCmds, constraint) 179 d.References.Table = nil 180 } 181 } 182 } 183 node.Cmds = normalizedCmds 184 } 185 186 // ValidationBehavior specifies whether or not a constraint is validated. 187 type ValidationBehavior int 188 189 const ( 190 // ValidationDefault is the default validation behavior (immediate). 191 ValidationDefault ValidationBehavior = iota 192 // ValidationSkip skips validation of any existing data. 193 ValidationSkip 194 ) 195 196 // AlterTableAddConstraint represents an ADD CONSTRAINT command. 197 type AlterTableAddConstraint struct { 198 ConstraintDef ConstraintTableDef 199 ValidationBehavior ValidationBehavior 200 } 201 202 // TelemetryCounter implements the AlterTableCmd interface. 203 func (node *AlterTableAddConstraint) TelemetryCounter() telemetry.Counter { 204 return sqltelemetry.SchemaChangeAlterCounterWithExtra("table", "add_constraint") 205 } 206 207 // Format implements the NodeFormatter interface. 208 func (node *AlterTableAddConstraint) Format(ctx *FmtCtx) { 209 ctx.WriteString(" ADD ") 210 ctx.FormatNode(node.ConstraintDef) 211 if node.ValidationBehavior == ValidationSkip { 212 ctx.WriteString(" NOT VALID") 213 } 214 } 215 216 // AlterTableAlterColumnType represents an ALTER TABLE ALTER COLUMN TYPE command. 217 type AlterTableAlterColumnType struct { 218 Collation string 219 Column Name 220 ToType ResolvableTypeReference 221 Using Expr 222 } 223 224 // TelemetryCounter implements the AlterTableCmd interface. 225 func (node *AlterTableAlterColumnType) TelemetryCounter() telemetry.Counter { 226 return sqltelemetry.SchemaChangeAlterCounterWithExtra("table", "alter_column_type") 227 } 228 229 // Format implements the NodeFormatter interface. 230 func (node *AlterTableAlterColumnType) Format(ctx *FmtCtx) { 231 ctx.WriteString(" ALTER COLUMN ") 232 ctx.FormatNode(&node.Column) 233 ctx.WriteString(" SET DATA TYPE ") 234 ctx.WriteString(node.ToType.SQLString()) 235 if len(node.Collation) > 0 { 236 ctx.WriteString(" COLLATE ") 237 ctx.WriteString(node.Collation) 238 } 239 if node.Using != nil { 240 ctx.WriteString(" USING ") 241 ctx.FormatNode(node.Using) 242 } 243 } 244 245 // GetColumn implements the ColumnMutationCmd interface. 246 func (node *AlterTableAlterColumnType) GetColumn() Name { 247 return node.Column 248 } 249 250 // AlterTableAlterPrimaryKey represents an ALTER TABLE ALTER PRIMARY KEY command. 251 type AlterTableAlterPrimaryKey struct { 252 Columns IndexElemList 253 Interleave *InterleaveDef 254 Sharded *ShardedIndexDef 255 } 256 257 // TelemetryCounter implements the AlterTableCmd interface. 258 func (node *AlterTableAlterPrimaryKey) TelemetryCounter() telemetry.Counter { 259 return sqltelemetry.SchemaChangeAlterCounterWithExtra("table", "alter_primary_key") 260 } 261 262 // Format implements the NodeFormatter interface. 263 func (node *AlterTableAlterPrimaryKey) Format(ctx *FmtCtx) { 264 ctx.WriteString(" ALTER PRIMARY KEY USING COLUMNS (") 265 ctx.FormatNode(&node.Columns) 266 ctx.WriteString(")") 267 if node.Sharded != nil { 268 ctx.FormatNode(node.Sharded) 269 } 270 if node.Interleave != nil { 271 ctx.FormatNode(node.Interleave) 272 } 273 } 274 275 // AlterTableDropColumn represents a DROP COLUMN command. 276 type AlterTableDropColumn struct { 277 IfExists bool 278 Column Name 279 DropBehavior DropBehavior 280 } 281 282 // TelemetryCounter implements the AlterTableCmd interface. 283 func (node *AlterTableDropColumn) TelemetryCounter() telemetry.Counter { 284 return sqltelemetry.SchemaChangeAlterCounterWithExtra("table", "drop_column") 285 } 286 287 // Format implements the NodeFormatter interface. 288 func (node *AlterTableDropColumn) Format(ctx *FmtCtx) { 289 ctx.WriteString(" DROP COLUMN ") 290 if node.IfExists { 291 ctx.WriteString("IF EXISTS ") 292 } 293 ctx.FormatNode(&node.Column) 294 if node.DropBehavior != DropDefault { 295 ctx.Printf(" %s", node.DropBehavior) 296 } 297 } 298 299 // AlterTableDropConstraint represents a DROP CONSTRAINT command. 300 type AlterTableDropConstraint struct { 301 IfExists bool 302 Constraint Name 303 DropBehavior DropBehavior 304 } 305 306 // TelemetryCounter implements the AlterTableCmd interface. 307 func (node *AlterTableDropConstraint) TelemetryCounter() telemetry.Counter { 308 return sqltelemetry.SchemaChangeAlterCounterWithExtra("table", "drop_constraint") 309 } 310 311 // Format implements the NodeFormatter interface. 312 func (node *AlterTableDropConstraint) Format(ctx *FmtCtx) { 313 ctx.WriteString(" DROP CONSTRAINT ") 314 if node.IfExists { 315 ctx.WriteString("IF EXISTS ") 316 } 317 ctx.FormatNode(&node.Constraint) 318 if node.DropBehavior != DropDefault { 319 ctx.Printf(" %s", node.DropBehavior) 320 } 321 } 322 323 // AlterTableValidateConstraint represents a VALIDATE CONSTRAINT command. 324 type AlterTableValidateConstraint struct { 325 Constraint Name 326 } 327 328 // TelemetryCounter implements the AlterTableCmd interface. 329 func (node *AlterTableValidateConstraint) TelemetryCounter() telemetry.Counter { 330 return sqltelemetry.SchemaChangeAlterCounterWithExtra("table", "validate_constraint") 331 } 332 333 // Format implements the NodeFormatter interface. 334 func (node *AlterTableValidateConstraint) Format(ctx *FmtCtx) { 335 ctx.WriteString(" VALIDATE CONSTRAINT ") 336 ctx.FormatNode(&node.Constraint) 337 } 338 339 // AlterTableRenameColumn represents an ALTER TABLE RENAME [COLUMN] command. 340 type AlterTableRenameColumn struct { 341 Column Name 342 NewName Name 343 } 344 345 // TelemetryCounter implements the AlterTableCmd interface. 346 func (node *AlterTableRenameColumn) TelemetryCounter() telemetry.Counter { 347 return sqltelemetry.SchemaChangeAlterCounterWithExtra("table", "rename_column") 348 } 349 350 // Format implements the NodeFormatter interface. 351 func (node *AlterTableRenameColumn) Format(ctx *FmtCtx) { 352 ctx.WriteString(" RENAME COLUMN ") 353 ctx.FormatNode(&node.Column) 354 ctx.WriteString(" TO ") 355 ctx.FormatNode(&node.NewName) 356 } 357 358 // AlterTableRenameConstraint represents an ALTER TABLE RENAME CONSTRAINT command. 359 type AlterTableRenameConstraint struct { 360 Constraint Name 361 NewName Name 362 } 363 364 // TelemetryCounter implements the AlterTableCmd interface. 365 func (node *AlterTableRenameConstraint) TelemetryCounter() telemetry.Counter { 366 return sqltelemetry.SchemaChangeAlterCounterWithExtra("table", "rename_constraint") 367 } 368 369 // Format implements the NodeFormatter interface. 370 func (node *AlterTableRenameConstraint) Format(ctx *FmtCtx) { 371 ctx.WriteString(" RENAME CONSTRAINT ") 372 ctx.FormatNode(&node.Constraint) 373 ctx.WriteString(" TO ") 374 ctx.FormatNode(&node.NewName) 375 } 376 377 // AlterTableSetDefault represents an ALTER COLUMN SET DEFAULT 378 // or DROP DEFAULT command. 379 type AlterTableSetDefault struct { 380 Column Name 381 Default Expr 382 } 383 384 // GetColumn implements the ColumnMutationCmd interface. 385 func (node *AlterTableSetDefault) GetColumn() Name { 386 return node.Column 387 } 388 389 // TelemetryCounter implements the AlterTableCmd interface. 390 func (node *AlterTableSetDefault) TelemetryCounter() telemetry.Counter { 391 return sqltelemetry.SchemaChangeAlterCounterWithExtra("table", "set_default") 392 } 393 394 // Format implements the NodeFormatter interface. 395 func (node *AlterTableSetDefault) Format(ctx *FmtCtx) { 396 ctx.WriteString(" ALTER COLUMN ") 397 ctx.FormatNode(&node.Column) 398 if node.Default == nil { 399 ctx.WriteString(" DROP DEFAULT") 400 } else { 401 ctx.WriteString(" SET DEFAULT ") 402 ctx.FormatNode(node.Default) 403 } 404 } 405 406 // AlterTableSetNotNull represents an ALTER COLUMN SET NOT NULL 407 // command. 408 type AlterTableSetNotNull struct { 409 Column Name 410 } 411 412 // GetColumn implements the ColumnMutationCmd interface. 413 func (node *AlterTableSetNotNull) GetColumn() Name { 414 return node.Column 415 } 416 417 // TelemetryCounter implements the AlterTableCmd interface. 418 func (node *AlterTableSetNotNull) TelemetryCounter() telemetry.Counter { 419 return sqltelemetry.SchemaChangeAlterCounterWithExtra("table", "set_not_null") 420 } 421 422 // Format implements the NodeFormatter interface. 423 func (node *AlterTableSetNotNull) Format(ctx *FmtCtx) { 424 ctx.WriteString(" ALTER COLUMN ") 425 ctx.FormatNode(&node.Column) 426 ctx.WriteString(" SET NOT NULL") 427 } 428 429 // AlterTableDropNotNull represents an ALTER COLUMN DROP NOT NULL 430 // command. 431 type AlterTableDropNotNull struct { 432 Column Name 433 } 434 435 // GetColumn implements the ColumnMutationCmd interface. 436 func (node *AlterTableDropNotNull) GetColumn() Name { 437 return node.Column 438 } 439 440 // TelemetryCounter implements the AlterTableCmd interface. 441 func (node *AlterTableDropNotNull) TelemetryCounter() telemetry.Counter { 442 return sqltelemetry.SchemaChangeAlterCounterWithExtra("table", "drop_not_null") 443 } 444 445 // Format implements the NodeFormatter interface. 446 func (node *AlterTableDropNotNull) Format(ctx *FmtCtx) { 447 ctx.WriteString(" ALTER COLUMN ") 448 ctx.FormatNode(&node.Column) 449 ctx.WriteString(" DROP NOT NULL") 450 } 451 452 // AlterTableDropStored represents an ALTER COLUMN DROP STORED command 453 // to remove the computed-ness from a column. 454 type AlterTableDropStored struct { 455 Column Name 456 } 457 458 // GetColumn implemnets the ColumnMutationCmd interface. 459 func (node *AlterTableDropStored) GetColumn() Name { 460 return node.Column 461 } 462 463 // TelemetryCounter implements the AlterTableCmd interface. 464 func (node *AlterTableDropStored) TelemetryCounter() telemetry.Counter { 465 return sqltelemetry.SchemaChangeAlterCounterWithExtra("table", "drop_stored") 466 } 467 468 // Format implements the NodeFormatter interface. 469 func (node *AlterTableDropStored) Format(ctx *FmtCtx) { 470 ctx.WriteString(" ALTER COLUMN ") 471 ctx.FormatNode(&node.Column) 472 ctx.WriteString(" DROP STORED") 473 } 474 475 // AlterTablePartitionBy represents an ALTER TABLE PARTITION BY 476 // command. 477 type AlterTablePartitionBy struct { 478 *PartitionBy 479 } 480 481 // TelemetryCounter implements the AlterTableCmd interface. 482 func (node *AlterTablePartitionBy) TelemetryCounter() telemetry.Counter { 483 return sqltelemetry.SchemaChangeAlterCounterWithExtra("table", "partition_by") 484 } 485 486 // Format implements the NodeFormatter interface. 487 func (node *AlterTablePartitionBy) Format(ctx *FmtCtx) { 488 ctx.FormatNode(node.PartitionBy) 489 } 490 491 // AuditMode represents a table audit mode 492 type AuditMode int 493 494 const ( 495 // AuditModeDisable is the default mode - no audit. 496 AuditModeDisable AuditMode = iota 497 // AuditModeReadWrite enables audit on read or write statements. 498 AuditModeReadWrite 499 ) 500 501 var auditModeName = [...]string{ 502 AuditModeDisable: "OFF", 503 AuditModeReadWrite: "READ WRITE", 504 } 505 506 func (m AuditMode) String() string { 507 return auditModeName[m] 508 } 509 510 // TelemetryName returns a friendly string for use in telemetry that represents 511 // the AuditMode. 512 func (m AuditMode) TelemetryName() string { 513 return strings.ReplaceAll(strings.ToLower(m.String()), " ", "_") 514 } 515 516 // AlterTableSetAudit represents an ALTER TABLE AUDIT SET statement. 517 type AlterTableSetAudit struct { 518 Mode AuditMode 519 } 520 521 // TelemetryCounter implements the AlterTableCmd interface. 522 func (node *AlterTableSetAudit) TelemetryCounter() telemetry.Counter { 523 return sqltelemetry.SchemaChangeAlterCounterWithExtra("table", "set_audit") 524 } 525 526 // Format implements the NodeFormatter interface. 527 func (node *AlterTableSetAudit) Format(ctx *FmtCtx) { 528 ctx.WriteString(" EXPERIMENTAL_AUDIT SET ") 529 ctx.WriteString(node.Mode.String()) 530 } 531 532 // AlterTableInjectStats represents an ALTER TABLE INJECT STATISTICS statement. 533 type AlterTableInjectStats struct { 534 Stats Expr 535 } 536 537 // TelemetryCounter implements the AlterTableCmd interface. 538 func (node *AlterTableInjectStats) TelemetryCounter() telemetry.Counter { 539 return sqltelemetry.SchemaChangeAlterCounterWithExtra("table", "inject_stats") 540 } 541 542 // Format implements the NodeFormatter interface. 543 func (node *AlterTableInjectStats) Format(ctx *FmtCtx) { 544 ctx.WriteString(" INJECT STATISTICS ") 545 ctx.FormatNode(node.Stats) 546 }