github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/rename_column.go (about)

     1  // Copyright 2017 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 sql
    12  
    13  import (
    14  	"context"
    15  
    16  	"github.com/cockroachdb/cockroach/pkg/sql/catalog/resolver"
    17  	"github.com/cockroachdb/cockroach/pkg/sql/parser"
    18  	"github.com/cockroachdb/cockroach/pkg/sql/pgwire/pgcode"
    19  	"github.com/cockroachdb/cockroach/pkg/sql/pgwire/pgerror"
    20  	"github.com/cockroachdb/cockroach/pkg/sql/privilege"
    21  	"github.com/cockroachdb/cockroach/pkg/sql/sem/tree"
    22  	"github.com/cockroachdb/cockroach/pkg/sql/sqlbase"
    23  	"github.com/cockroachdb/errors"
    24  )
    25  
    26  var errEmptyColumnName = pgerror.New(pgcode.Syntax, "empty column name")
    27  
    28  type renameColumnNode struct {
    29  	n         *tree.RenameColumn
    30  	tableDesc *sqlbase.MutableTableDescriptor
    31  }
    32  
    33  // RenameColumn renames the column.
    34  // Privileges: CREATE on table.
    35  //   notes: postgres requires CREATE on the table.
    36  //          mysql requires ALTER, CREATE, INSERT on the table.
    37  func (p *planner) RenameColumn(ctx context.Context, n *tree.RenameColumn) (planNode, error) {
    38  	// Check if table exists.
    39  	tableDesc, err := p.ResolveMutableTableDescriptor(ctx, &n.Table, !n.IfExists, resolver.ResolveRequireTableDesc)
    40  	if err != nil {
    41  		return nil, err
    42  	}
    43  	if tableDesc == nil {
    44  		return newZeroNode(nil /* columns */), nil
    45  	}
    46  
    47  	if err := p.CheckPrivilege(ctx, tableDesc, privilege.CREATE); err != nil {
    48  		return nil, err
    49  	}
    50  
    51  	return &renameColumnNode{n: n, tableDesc: tableDesc}, nil
    52  }
    53  
    54  // ReadingOwnWrites implements the planNodeReadingOwnWrites interface.
    55  // This is because RENAME COLUMN performs multiple KV operations on descriptors
    56  // and expects to see its own writes.
    57  func (n *renameColumnNode) ReadingOwnWrites() {}
    58  
    59  func (n *renameColumnNode) startExec(params runParams) error {
    60  	p := params.p
    61  	ctx := params.ctx
    62  	tableDesc := n.tableDesc
    63  
    64  	const allowRenameOfShardColumn = false
    65  	descChanged, err := params.p.renameColumn(params.ctx, tableDesc, &n.n.Name,
    66  		&n.n.NewName, allowRenameOfShardColumn)
    67  	if err != nil {
    68  		return err
    69  	}
    70  
    71  	if !descChanged {
    72  		return nil
    73  	}
    74  
    75  	if err := tableDesc.Validate(ctx, p.txn, p.ExecCfg().Codec); err != nil {
    76  		return err
    77  	}
    78  
    79  	return p.writeSchemaChange(
    80  		ctx, tableDesc, sqlbase.InvalidMutationID, tree.AsStringWithFQNames(n.n, params.Ann()))
    81  }
    82  
    83  // renameColumn will rename the column in tableDesc from oldName to newName.
    84  // If allowRenameOfShardColumn is false, this method will return an error if
    85  // the column being renamed is a generated column for a hash sharded index.
    86  func (p *planner) renameColumn(
    87  	ctx context.Context,
    88  	tableDesc *sqlbase.MutableTableDescriptor,
    89  	oldName, newName *tree.Name,
    90  	allowRenameOfShardColumn bool,
    91  ) (changed bool, err error) {
    92  	if *newName == "" {
    93  		return false, errEmptyColumnName
    94  	}
    95  
    96  	col, _, err := tableDesc.FindColumnByName(*oldName)
    97  	if err != nil {
    98  		return false, err
    99  	}
   100  
   101  	for _, tableRef := range tableDesc.DependedOnBy {
   102  		found := false
   103  		for _, colID := range tableRef.ColumnIDs {
   104  			if colID == col.ID {
   105  				found = true
   106  			}
   107  		}
   108  		if found {
   109  			return false, p.dependentViewRenameError(
   110  				ctx, "column", oldName.String(), tableDesc.ParentID, tableRef.ID)
   111  		}
   112  	}
   113  	if *oldName == *newName {
   114  		// Noop.
   115  		return false, nil
   116  	}
   117  	isShardColumn := tableDesc.IsShardColumn(col)
   118  	if isShardColumn && !allowRenameOfShardColumn {
   119  		return false, pgerror.Newf(pgcode.ReservedName, "cannot rename shard column")
   120  	}
   121  	// Understand if the active column already exists before checking for column
   122  	// mutations to detect assertion failure of empty mutation and no column.
   123  	// Otherwise we would have to make the above call twice.
   124  	_, columnNotFoundErr := tableDesc.FindActiveColumnByName(string(*newName))
   125  	if m := tableDesc.FindColumnMutationByName(*newName); m != nil {
   126  		switch m.Direction {
   127  		case sqlbase.DescriptorMutation_ADD:
   128  			return false, pgerror.Newf(pgcode.DuplicateColumn,
   129  				"duplicate: column %q in the middle of being added, not yet public",
   130  				col.Name)
   131  		case sqlbase.DescriptorMutation_DROP:
   132  			return false, pgerror.Newf(pgcode.ObjectNotInPrerequisiteState,
   133  				"column %q being dropped, try again later", col.Name)
   134  		default:
   135  			if columnNotFoundErr != nil {
   136  				return false, errors.AssertionFailedf(
   137  					"mutation in state %s, direction %s, and no column descriptor",
   138  					errors.Safe(m.State), errors.Safe(m.Direction))
   139  			}
   140  		}
   141  	}
   142  	if columnNotFoundErr == nil {
   143  		return false, sqlbase.NewColumnAlreadyExistsError(tree.ErrString(newName), tableDesc.Name)
   144  	}
   145  
   146  	preFn := func(expr tree.Expr) (recurse bool, newExpr tree.Expr, err error) {
   147  		if vBase, ok := expr.(tree.VarName); ok {
   148  			v, err := vBase.NormalizeVarName()
   149  			if err != nil {
   150  				return false, nil, err
   151  			}
   152  			if c, ok := v.(*tree.ColumnItem); ok {
   153  				if string(c.ColumnName) == string(*oldName) {
   154  					c.ColumnName = *newName
   155  				}
   156  			}
   157  			return false, v, nil
   158  		}
   159  		return true, expr, nil
   160  	}
   161  
   162  	renameIn := func(expression string) (string, error) {
   163  		parsed, err := parser.ParseExpr(expression)
   164  		if err != nil {
   165  			return "", err
   166  		}
   167  
   168  		renamed, err := tree.SimpleVisit(parsed, preFn)
   169  		if err != nil {
   170  			return "", err
   171  		}
   172  
   173  		return renamed.String(), nil
   174  	}
   175  
   176  	// Rename the column in CHECK constraints.
   177  	// Renaming columns that are being referenced by checks that are being added is not allowed.
   178  	for i := range tableDesc.Checks {
   179  		var err error
   180  		tableDesc.Checks[i].Expr, err = renameIn(tableDesc.Checks[i].Expr)
   181  		if err != nil {
   182  			return false, err
   183  		}
   184  	}
   185  
   186  	// Rename the column in computed columns.
   187  	for i := range tableDesc.Columns {
   188  		if otherCol := &tableDesc.Columns[i]; otherCol.IsComputed() {
   189  			newExpr, err := renameIn(*otherCol.ComputeExpr)
   190  			if err != nil {
   191  				return false, err
   192  			}
   193  			otherCol.ComputeExpr = &newExpr
   194  		}
   195  	}
   196  
   197  	// Rename the column in hash-sharded index descriptors. Potentially rename the
   198  	// shard column too if we haven't already done it.
   199  	shardColumnsToRename := make(map[tree.Name]tree.Name) // map[oldShardColName]newShardColName
   200  	maybeUpdateShardedDesc := func(shardedDesc *sqlbase.ShardedDescriptor) {
   201  		if !shardedDesc.IsSharded {
   202  			return
   203  		}
   204  		oldShardColName := tree.Name(sqlbase.GetShardColumnName(
   205  			shardedDesc.ColumnNames, shardedDesc.ShardBuckets))
   206  		var changed bool
   207  		for i, c := range shardedDesc.ColumnNames {
   208  			if c == string(*oldName) {
   209  				changed = true
   210  				shardedDesc.ColumnNames[i] = string(*newName)
   211  			}
   212  		}
   213  		if !changed {
   214  			return
   215  		}
   216  		newName, alreadyRenamed := shardColumnsToRename[oldShardColName]
   217  		if !alreadyRenamed {
   218  			newName = tree.Name(sqlbase.GetShardColumnName(
   219  				shardedDesc.ColumnNames, shardedDesc.ShardBuckets))
   220  			shardColumnsToRename[oldShardColName] = newName
   221  		}
   222  		// Keep the shardedDesc name in sync with the column name.
   223  		shardedDesc.Name = string(newName)
   224  	}
   225  	for _, idx := range tableDesc.AllNonDropIndexes() {
   226  		maybeUpdateShardedDesc(&idx.Sharded)
   227  	}
   228  
   229  	// Rename the column in the indexes.
   230  	tableDesc.RenameColumnDescriptor(col, string(*newName))
   231  
   232  	// Rename any shard columns which need to be renamed because their name was
   233  	// based on this column.
   234  	for oldShardColName, newShardColName := range shardColumnsToRename {
   235  		// Recursively call p.renameColumn. We don't need to worry about deeper than
   236  		// one recursive call because shard columns cannot refer to each other.
   237  		const allowRenameOfShardColumn = true
   238  		_, err = p.renameColumn(ctx, tableDesc, &oldShardColName, &newShardColName,
   239  			allowRenameOfShardColumn)
   240  		if err != nil {
   241  			return false, err
   242  		}
   243  	}
   244  
   245  	return true, nil
   246  }
   247  
   248  func (n *renameColumnNode) Next(runParams) (bool, error) { return false, nil }
   249  func (n *renameColumnNode) Values() tree.Datums          { return tree.Datums{} }
   250  func (n *renameColumnNode) Close(context.Context)        {}