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  }