github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/drop_sequence.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/server/telemetry"
    17  	"github.com/cockroachdb/cockroach/pkg/sql/catalog/resolver"
    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/sem/tree"
    21  	"github.com/cockroachdb/cockroach/pkg/sql/sqlbase"
    22  	"github.com/cockroachdb/cockroach/pkg/sql/sqltelemetry"
    23  	"github.com/cockroachdb/cockroach/pkg/util/errorutil/unimplemented"
    24  )
    25  
    26  type dropSequenceNode struct {
    27  	n  *tree.DropSequence
    28  	td []toDelete
    29  }
    30  
    31  func (p *planner) DropSequence(ctx context.Context, n *tree.DropSequence) (planNode, error) {
    32  	td := make([]toDelete, 0, len(n.Names))
    33  	for i := range n.Names {
    34  		tn := &n.Names[i]
    35  		droppedDesc, err := p.prepareDrop(ctx, tn, !n.IfExists, resolver.ResolveRequireSequenceDesc)
    36  		if err != nil {
    37  			return nil, err
    38  		}
    39  		if droppedDesc == nil {
    40  			// IfExists specified and descriptor does not exist.
    41  			continue
    42  		}
    43  
    44  		if depErr := p.sequenceDependencyError(ctx, droppedDesc); depErr != nil {
    45  			return nil, depErr
    46  		}
    47  
    48  		td = append(td, toDelete{tn, droppedDesc})
    49  	}
    50  
    51  	if len(td) == 0 {
    52  		return newZeroNode(nil /* columns */), nil
    53  	}
    54  
    55  	return &dropSequenceNode{
    56  		n:  n,
    57  		td: td,
    58  	}, nil
    59  }
    60  
    61  // ReadingOwnWrites implements the planNodeReadingOwnWrites interface.
    62  // This is because DROP SEQUENCE performs multiple KV operations on descriptors
    63  // and expects to see its own writes.
    64  func (n *dropSequenceNode) ReadingOwnWrites() {}
    65  
    66  func (n *dropSequenceNode) startExec(params runParams) error {
    67  	telemetry.Inc(sqltelemetry.SchemaChangeDropCounter("sequence"))
    68  
    69  	ctx := params.ctx
    70  	for _, toDel := range n.td {
    71  		droppedDesc := toDel.desc
    72  		err := params.p.dropSequenceImpl(
    73  			ctx, droppedDesc, true /* queueJob */, tree.AsStringWithFQNames(n.n, params.Ann()), n.n.DropBehavior,
    74  		)
    75  		if err != nil {
    76  			return err
    77  		}
    78  		// Log a Drop Sequence event for this table. This is an auditable log event
    79  		// and is recorded in the same transaction as the table descriptor
    80  		// update.
    81  		if err := MakeEventLogger(params.extendedEvalCtx.ExecCfg).InsertEventRecord(
    82  			ctx,
    83  			params.p.txn,
    84  			EventLogDropSequence,
    85  			int32(droppedDesc.ID),
    86  			int32(params.extendedEvalCtx.NodeID.SQLInstanceID()),
    87  			struct {
    88  				SequenceName string
    89  				Statement    string
    90  				User         string
    91  			}{toDel.tn.FQString(), n.n.String(), params.SessionData().User},
    92  		); err != nil {
    93  			return err
    94  		}
    95  	}
    96  	return nil
    97  }
    98  
    99  func (*dropSequenceNode) Next(runParams) (bool, error) { return false, nil }
   100  func (*dropSequenceNode) Values() tree.Datums          { return tree.Datums{} }
   101  func (*dropSequenceNode) Close(context.Context)        {}
   102  
   103  func (p *planner) dropSequenceImpl(
   104  	ctx context.Context,
   105  	seqDesc *sqlbase.MutableTableDescriptor,
   106  	queueJob bool,
   107  	jobDesc string,
   108  	behavior tree.DropBehavior,
   109  ) error {
   110  	return p.initiateDropTable(ctx, seqDesc, queueJob, jobDesc, true /* drainName */)
   111  }
   112  
   113  // sequenceDependency error returns an error if the given sequence cannot be dropped because
   114  // a table uses it in a DEFAULT expression on one of its columns, or nil if there is no
   115  // such dependency.
   116  func (p *planner) sequenceDependencyError(
   117  	ctx context.Context, droppedDesc *sqlbase.MutableTableDescriptor,
   118  ) error {
   119  	if len(droppedDesc.DependedOnBy) > 0 {
   120  		return pgerror.Newf(
   121  			pgcode.DependentObjectsStillExist,
   122  			"cannot drop sequence %s because other objects depend on it",
   123  			droppedDesc.Name,
   124  		)
   125  	}
   126  	return nil
   127  }
   128  
   129  func (p *planner) canRemoveAllTableOwnedSequences(
   130  	ctx context.Context, desc *sqlbase.MutableTableDescriptor, behavior tree.DropBehavior,
   131  ) error {
   132  	for _, col := range desc.Columns {
   133  		err := p.canRemoveOwnedSequencesImpl(ctx, desc, &col, behavior, false /* isColumnDrop */)
   134  		if err != nil {
   135  			return err
   136  		}
   137  	}
   138  	return nil
   139  }
   140  
   141  func (p *planner) canRemoveAllColumnOwnedSequences(
   142  	ctx context.Context,
   143  	desc *sqlbase.MutableTableDescriptor,
   144  	col *sqlbase.ColumnDescriptor,
   145  	behavior tree.DropBehavior,
   146  ) error {
   147  	return p.canRemoveOwnedSequencesImpl(ctx, desc, col, behavior, true /* isColumnDrop */)
   148  }
   149  
   150  func (p *planner) canRemoveOwnedSequencesImpl(
   151  	ctx context.Context,
   152  	desc *sqlbase.MutableTableDescriptor,
   153  	col *sqlbase.ColumnDescriptor,
   154  	behavior tree.DropBehavior,
   155  	isColumnDrop bool,
   156  ) error {
   157  	for _, sequenceID := range col.OwnsSequenceIds {
   158  		seqLookup, err := p.LookupTableByID(ctx, sequenceID)
   159  		if err != nil {
   160  			return err
   161  		}
   162  		seqDesc := seqLookup.Desc
   163  		affectsNoColumns := len(seqDesc.DependedOnBy) == 0
   164  		// It is okay if the sequence is depended on by columns that are being
   165  		// dropped in the same transaction
   166  		canBeSafelyRemoved := len(seqDesc.DependedOnBy) == 1 && seqDesc.DependedOnBy[0].ID == desc.ID
   167  		// If only the column is being dropped, no other columns of the table can
   168  		// depend on that sequence either
   169  		if isColumnDrop {
   170  			canBeSafelyRemoved = canBeSafelyRemoved && len(seqDesc.DependedOnBy[0].ColumnIDs) == 1 &&
   171  				seqDesc.DependedOnBy[0].ColumnIDs[0] == col.ID
   172  		}
   173  
   174  		canRemove := affectsNoColumns || canBeSafelyRemoved
   175  
   176  		// Once Drop Sequence Cascade actually respects the drop behavior, this
   177  		// check should go away.
   178  		if behavior == tree.DropCascade && !canRemove {
   179  			return unimplemented.NewWithIssue(20965, "DROP SEQUENCE CASCADE is currently unimplemented")
   180  		}
   181  		// If Cascade is not enabled, and more than 1 columns depend on it, and the
   182  		if behavior != tree.DropCascade && !canRemove {
   183  			return pgerror.Newf(
   184  				pgcode.DependentObjectsStillExist,
   185  				"cannot drop table %s because other objects depend on it",
   186  				desc.Name,
   187  			)
   188  		}
   189  	}
   190  	return nil
   191  }