github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/drop_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 sql
    12  
    13  import (
    14  	"context"
    15  	"fmt"
    16  	"strings"
    17  
    18  	"github.com/cockroachdb/cockroach/pkg/roachpb"
    19  	"github.com/cockroachdb/cockroach/pkg/security"
    20  	"github.com/cockroachdb/cockroach/pkg/server/telemetry"
    21  	"github.com/cockroachdb/cockroach/pkg/sql/catalog/resolver"
    22  	"github.com/cockroachdb/cockroach/pkg/sql/privilege"
    23  	"github.com/cockroachdb/cockroach/pkg/sql/sem/tree"
    24  	"github.com/cockroachdb/cockroach/pkg/sql/sqlbase"
    25  	"github.com/cockroachdb/cockroach/pkg/sql/sqltelemetry"
    26  	"github.com/cockroachdb/cockroach/pkg/util/errorutil/unimplemented"
    27  	"github.com/cockroachdb/cockroach/pkg/util/hlc"
    28  	"github.com/cockroachdb/cockroach/pkg/util/timeutil"
    29  	"github.com/cockroachdb/errors"
    30  )
    31  
    32  type dropTableNode struct {
    33  	n *tree.DropTable
    34  	// td is a map from table descriptor to toDelete struct, indicating which
    35  	// tables this operation should delete.
    36  	td map[sqlbase.ID]toDelete
    37  }
    38  
    39  type toDelete struct {
    40  	tn   *tree.TableName
    41  	desc *sqlbase.MutableTableDescriptor
    42  }
    43  
    44  // DropTable drops a table.
    45  // Privileges: DROP on table.
    46  //   Notes: postgres allows only the table owner to DROP a table.
    47  //          mysql requires the DROP privilege on the table.
    48  func (p *planner) DropTable(ctx context.Context, n *tree.DropTable) (planNode, error) {
    49  	td := make(map[sqlbase.ID]toDelete, len(n.Names))
    50  	for i := range n.Names {
    51  		tn := &n.Names[i]
    52  		droppedDesc, err := p.prepareDrop(ctx, tn, !n.IfExists, resolver.ResolveRequireTableDesc)
    53  		if err != nil {
    54  			return nil, err
    55  		}
    56  		if droppedDesc == nil {
    57  			continue
    58  		}
    59  
    60  		td[droppedDesc.ID] = toDelete{tn, droppedDesc}
    61  	}
    62  
    63  	for _, toDel := range td {
    64  		droppedDesc := toDel.desc
    65  		for i := range droppedDesc.InboundFKs {
    66  			ref := &droppedDesc.InboundFKs[i]
    67  			if _, ok := td[ref.OriginTableID]; !ok {
    68  				if err := p.canRemoveFKBackreference(ctx, droppedDesc.Name, ref, n.DropBehavior); err != nil {
    69  					return nil, err
    70  				}
    71  			}
    72  		}
    73  		for _, idx := range droppedDesc.AllNonDropIndexes() {
    74  			for _, ref := range idx.InterleavedBy {
    75  				if _, ok := td[ref.Table]; !ok {
    76  					if err := p.canRemoveInterleave(ctx, droppedDesc.Name, ref, n.DropBehavior); err != nil {
    77  						return nil, err
    78  					}
    79  				}
    80  			}
    81  		}
    82  		for _, ref := range droppedDesc.DependedOnBy {
    83  			if _, ok := td[ref.ID]; !ok {
    84  				if err := p.canRemoveDependentView(ctx, droppedDesc, ref, n.DropBehavior); err != nil {
    85  					return nil, err
    86  				}
    87  			}
    88  		}
    89  		if err := p.canRemoveAllTableOwnedSequences(ctx, droppedDesc, n.DropBehavior); err != nil {
    90  			return nil, err
    91  		}
    92  
    93  	}
    94  
    95  	if len(td) == 0 {
    96  		return newZeroNode(nil /* columns */), nil
    97  	}
    98  	return &dropTableNode{n: n, td: td}, nil
    99  }
   100  
   101  // ReadingOwnWrites implements the planNodeReadingOwnWrites interface.
   102  // This is because DROP TABLE performs multiple KV operations on descriptors
   103  // and expects to see its own writes.
   104  func (n *dropTableNode) ReadingOwnWrites() {}
   105  
   106  func (n *dropTableNode) startExec(params runParams) error {
   107  	telemetry.Inc(sqltelemetry.SchemaChangeDropCounter("table"))
   108  
   109  	ctx := params.ctx
   110  	for _, toDel := range n.td {
   111  		droppedDesc := toDel.desc
   112  		if droppedDesc == nil {
   113  			continue
   114  		}
   115  
   116  		droppedViews, err := params.p.dropTableImpl(ctx, droppedDesc, true /* queueJob */, tree.AsStringWithFQNames(n.n, params.Ann()))
   117  		if err != nil {
   118  			return err
   119  		}
   120  		// Log a Drop Table event for this table. This is an auditable log event
   121  		// and is recorded in the same transaction as the table descriptor
   122  		// update.
   123  		if err := MakeEventLogger(params.extendedEvalCtx.ExecCfg).InsertEventRecord(
   124  			ctx,
   125  			params.p.txn,
   126  			EventLogDropTable,
   127  			int32(droppedDesc.ID),
   128  			int32(params.extendedEvalCtx.NodeID.SQLInstanceID()),
   129  			struct {
   130  				TableName           string
   131  				Statement           string
   132  				User                string
   133  				CascadeDroppedViews []string
   134  			}{toDel.tn.FQString(), n.n.String(),
   135  				params.SessionData().User, droppedViews},
   136  		); err != nil {
   137  			return err
   138  		}
   139  	}
   140  	return nil
   141  }
   142  
   143  func (*dropTableNode) Next(runParams) (bool, error) { return false, nil }
   144  func (*dropTableNode) Values() tree.Datums          { return tree.Datums{} }
   145  func (*dropTableNode) Close(context.Context)        {}
   146  
   147  // prepareDrop/dropTableImpl is used to drop a single table by
   148  // name, which can result from a DROP TABLE, DROP VIEW, DROP SEQUENCE,
   149  // or DROP DATABASE statement. This method returns the dropped table
   150  // descriptor, to be used for the purpose of logging the event.  The table
   151  // is not actually truncated or deleted synchronously. Instead, it is marked
   152  // as deleted (meaning up_version is set and deleted is set) and the
   153  // actual deletion happens async in a schema changer. Note that,
   154  // courtesy of up_version, the actual truncation and dropping will
   155  // only happen once every node ACKs the version of the descriptor with
   156  // the deleted bit set, meaning the lease manager will not hand out
   157  // new leases for it and existing leases are released).
   158  // If the table does not exist, this function returns a nil descriptor.
   159  func (p *planner) prepareDrop(
   160  	ctx context.Context,
   161  	name *tree.TableName,
   162  	required bool,
   163  	requiredType resolver.ResolveRequiredType,
   164  ) (*sqlbase.MutableTableDescriptor, error) {
   165  	tableDesc, err := p.ResolveMutableTableDescriptor(ctx, name, required, requiredType)
   166  	if err != nil {
   167  		return nil, err
   168  	}
   169  	if tableDesc == nil {
   170  		return nil, err
   171  	}
   172  	if err := p.prepareDropWithTableDesc(ctx, tableDesc); err != nil {
   173  		return nil, err
   174  	}
   175  	return tableDesc, nil
   176  }
   177  
   178  // prepareDropWithTableDesc behaves as prepareDrop, except it assumes the
   179  // table descriptor is already fetched. This is useful for DropDatabase,
   180  // as prepareDrop requires resolving a TableName when DropDatabase already
   181  // has it resolved.
   182  func (p *planner) prepareDropWithTableDesc(
   183  	ctx context.Context, tableDesc *sqlbase.MutableTableDescriptor,
   184  ) error {
   185  	return p.CheckPrivilege(ctx, tableDesc, privilege.DROP)
   186  }
   187  
   188  // canRemoveFKBackReference returns an error if the input backreference isn't
   189  // allowed to be removed.
   190  func (p *planner) canRemoveFKBackreference(
   191  	ctx context.Context, from string, ref *sqlbase.ForeignKeyConstraint, behavior tree.DropBehavior,
   192  ) error {
   193  	table, err := p.Tables().GetMutableTableVersionByID(ctx, ref.OriginTableID, p.txn)
   194  	if err != nil {
   195  		return err
   196  	}
   197  	if behavior != tree.DropCascade {
   198  		return fmt.Errorf("%q is referenced by foreign key from table %q", from, table.Name)
   199  	}
   200  	// Check to see whether we're allowed to edit the table that has a
   201  	// foreign key constraint on the table that we're dropping right now.
   202  	return p.CheckPrivilege(ctx, table, privilege.CREATE)
   203  }
   204  
   205  func (p *planner) canRemoveInterleave(
   206  	ctx context.Context, from string, ref sqlbase.ForeignKeyReference, behavior tree.DropBehavior,
   207  ) error {
   208  	table, err := p.Tables().GetMutableTableVersionByID(ctx, ref.Table, p.txn)
   209  	if err != nil {
   210  		return err
   211  	}
   212  	// TODO(dan): It's possible to DROP a table that has a child interleave, but
   213  	// some loose ends would have to be addressed. The zone would have to be
   214  	// kept and deleted when the last table in it is removed. Also, the dropped
   215  	// table's descriptor would have to be kept around in some Dropped but
   216  	// non-public state for referential integrity of the `InterleaveDescriptor`
   217  	// pointers.
   218  	if behavior != tree.DropCascade {
   219  		return unimplemented.NewWithIssuef(
   220  			8036, "%q is interleaved by table %q", from, table.Name)
   221  	}
   222  	return p.CheckPrivilege(ctx, table, privilege.CREATE)
   223  }
   224  
   225  func (p *planner) removeInterleave(ctx context.Context, ref sqlbase.ForeignKeyReference) error {
   226  	table, err := p.Tables().GetMutableTableVersionByID(ctx, ref.Table, p.txn)
   227  	if err != nil {
   228  		return err
   229  	}
   230  	if table.Dropped() {
   231  		// The referenced table is being dropped. No need to modify it further.
   232  		return nil
   233  	}
   234  	idx, err := table.FindIndexByID(ref.Index)
   235  	if err != nil {
   236  		return err
   237  	}
   238  	idx.Interleave.Ancestors = nil
   239  	// No job description, since this is presumably part of some larger schema change.
   240  	return p.writeSchemaChange(ctx, table, sqlbase.InvalidMutationID, "")
   241  }
   242  
   243  // dropTableImpl does the work of dropping a table (and everything that depends
   244  // on it if `cascade` is enabled). It returns a list of view names that were
   245  // dropped due to `cascade` behavior.
   246  func (p *planner) dropTableImpl(
   247  	ctx context.Context, tableDesc *sqlbase.MutableTableDescriptor, queueJob bool, jobDesc string,
   248  ) ([]string, error) {
   249  	var droppedViews []string
   250  
   251  	// Remove foreign key back references from tables that this table has foreign
   252  	// keys to.
   253  	for i := range tableDesc.OutboundFKs {
   254  		ref := &tableDesc.OutboundFKs[i]
   255  		if err := p.removeFKBackReference(ctx, tableDesc, ref); err != nil {
   256  			return droppedViews, err
   257  		}
   258  	}
   259  	tableDesc.OutboundFKs = nil
   260  
   261  	// Remove foreign key forward references from tables that have foreign keys
   262  	// to this table.
   263  	for i := range tableDesc.InboundFKs {
   264  		ref := &tableDesc.InboundFKs[i]
   265  		if err := p.removeFKForBackReference(ctx, tableDesc, ref); err != nil {
   266  			return droppedViews, err
   267  		}
   268  	}
   269  	tableDesc.InboundFKs = nil
   270  
   271  	// Remove interleave relationships.
   272  	for _, idx := range tableDesc.AllNonDropIndexes() {
   273  		if len(idx.Interleave.Ancestors) > 0 {
   274  			if err := p.removeInterleaveBackReference(ctx, tableDesc, idx); err != nil {
   275  				return droppedViews, err
   276  			}
   277  		}
   278  		for _, ref := range idx.InterleavedBy {
   279  			if err := p.removeInterleave(ctx, ref); err != nil {
   280  				return droppedViews, err
   281  			}
   282  		}
   283  	}
   284  
   285  	// Remove sequence dependencies.
   286  	for i := range tableDesc.Columns {
   287  		if err := p.removeSequenceDependencies(ctx, tableDesc, &tableDesc.Columns[i]); err != nil {
   288  			return droppedViews, err
   289  		}
   290  	}
   291  
   292  	// Drop sequences that the columns of the table own
   293  	for _, col := range tableDesc.Columns {
   294  		if err := p.dropSequencesOwnedByCol(ctx, &col); err != nil {
   295  			return droppedViews, err
   296  		}
   297  	}
   298  
   299  	// Drop all views that depend on this table, assuming that we wouldn't have
   300  	// made it to this point if `cascade` wasn't enabled.
   301  	for _, ref := range tableDesc.DependedOnBy {
   302  		viewDesc, err := p.getViewDescForCascade(
   303  			ctx, tableDesc.TypeName(), tableDesc.Name, tableDesc.ParentID, ref.ID, tree.DropCascade,
   304  		)
   305  		if err != nil {
   306  			return droppedViews, err
   307  		}
   308  		// This view is already getting dropped. Don't do it twice.
   309  		if viewDesc.Dropped() {
   310  			continue
   311  		}
   312  		// TODO (lucy): Have more consistent/informative names for dependent jobs.
   313  		cascadedViews, err := p.dropViewImpl(ctx, viewDesc, queueJob, "dropping dependent view", tree.DropCascade)
   314  		if err != nil {
   315  			return droppedViews, err
   316  		}
   317  		droppedViews = append(droppedViews, cascadedViews...)
   318  		droppedViews = append(droppedViews, viewDesc.Name)
   319  	}
   320  
   321  	err := p.removeTableComments(ctx, tableDesc)
   322  	if err != nil {
   323  		return droppedViews, err
   324  	}
   325  
   326  	err = p.initiateDropTable(ctx, tableDesc, queueJob, jobDesc, true /* drain name */)
   327  	return droppedViews, err
   328  }
   329  
   330  // drainName when set implies that the name needs to go through the draining
   331  // names process. This parameter is always passed in as true except from
   332  // TRUNCATE which directly deletes the old name to id map and doesn't need
   333  // drain the old map.
   334  func (p *planner) initiateDropTable(
   335  	ctx context.Context,
   336  	tableDesc *sqlbase.MutableTableDescriptor,
   337  	queueJob bool,
   338  	jobDesc string,
   339  	drainName bool,
   340  ) error {
   341  	if tableDesc.Dropped() {
   342  		return fmt.Errorf("table %q is being dropped", tableDesc.Name)
   343  	}
   344  
   345  	// If the table is not interleaved , use the delayed GC mechanism to
   346  	// schedule usage of the more efficient ClearRange pathway. ClearRange will
   347  	// only work if the entire hierarchy of interleaved tables are dropped at
   348  	// once, as with ON DELETE CASCADE where the top-level "root" table is
   349  	// dropped.
   350  	//
   351  	// TODO(bram): If interleaved and ON DELETE CASCADE, we will be able to use
   352  	// this faster mechanism.
   353  	if tableDesc.IsTable() && !tableDesc.IsInterleaved() {
   354  		// Get the zone config applying to this table in order to
   355  		// ensure there is a GC TTL.
   356  		_, _, _, err := GetZoneConfigInTxn(
   357  			ctx, p.txn, uint32(tableDesc.ID), &sqlbase.IndexDescriptor{}, "", false, /* getInheritedDefault */
   358  		)
   359  		if err != nil {
   360  			return err
   361  		}
   362  
   363  		tableDesc.DropTime = timeutil.Now().UnixNano()
   364  	}
   365  
   366  	// Unsplit all manually split ranges in the table so they can be
   367  	// automatically merged by the merge queue.
   368  	ranges, err := ScanMetaKVs(ctx, p.txn, tableDesc.TableSpan(p.ExecCfg().Codec))
   369  	if err != nil {
   370  		return err
   371  	}
   372  	for _, r := range ranges {
   373  		var desc roachpb.RangeDescriptor
   374  		if err := r.ValueProto(&desc); err != nil {
   375  			return err
   376  		}
   377  		if (desc.GetStickyBit() != hlc.Timestamp{}) {
   378  			// Swallow "key is not the start of a range" errors because it would mean
   379  			// that the sticky bit was removed and merged concurrently. DROP TABLE
   380  			// should not fail because of this.
   381  			if err := p.ExecCfg().DB.AdminUnsplit(ctx, desc.StartKey); err != nil && !strings.Contains(err.Error(), "is not the start of a range") {
   382  				return err
   383  			}
   384  		}
   385  	}
   386  
   387  	tableDesc.State = sqlbase.TableDescriptor_DROP
   388  	if drainName {
   389  		parentSchemaID := tableDesc.GetParentSchemaID()
   390  
   391  		// Queue up name for draining.
   392  		nameDetails := sqlbase.TableDescriptor_NameInfo{
   393  			ParentID:       tableDesc.ParentID,
   394  			ParentSchemaID: parentSchemaID,
   395  			Name:           tableDesc.Name}
   396  		tableDesc.DrainingNames = append(tableDesc.DrainingNames, nameDetails)
   397  	}
   398  
   399  	// Mark all jobs scheduled for schema changes as successful.
   400  	jobIDs := make(map[int64]struct{})
   401  	var id sqlbase.MutationID
   402  	for _, m := range tableDesc.Mutations {
   403  		if id != m.MutationID {
   404  			id = m.MutationID
   405  			jobID, err := getJobIDForMutationWithDescriptor(ctx, tableDesc.TableDesc(), id)
   406  			if err != nil {
   407  				return err
   408  			}
   409  			jobIDs[jobID] = struct{}{}
   410  		}
   411  	}
   412  	for jobID := range jobIDs {
   413  		if err := p.ExecCfg().JobRegistry.Succeeded(ctx, p.txn, jobID); err != nil {
   414  			return errors.Wrapf(err,
   415  				"failed to mark job %d as as successful", errors.Safe(jobID))
   416  		}
   417  	}
   418  	// Initiate an immediate schema change. When dropping a table
   419  	// in a session, the data and the descriptor are not deleted.
   420  	// Instead, that is taken care of asynchronously by the schema
   421  	// change manager, which is notified via a system config gossip.
   422  	// The schema change manager will properly schedule deletion of
   423  	// the underlying data when the GC deadline expires.
   424  	return p.writeDropTable(ctx, tableDesc, queueJob, jobDesc)
   425  }
   426  
   427  func (p *planner) removeFKForBackReference(
   428  	ctx context.Context, tableDesc *sqlbase.MutableTableDescriptor, ref *sqlbase.ForeignKeyConstraint,
   429  ) error {
   430  	var originTableDesc *sqlbase.MutableTableDescriptor
   431  	// We don't want to lookup/edit a second copy of the same table.
   432  	if tableDesc.ID == ref.OriginTableID {
   433  		originTableDesc = tableDesc
   434  	} else {
   435  		lookup, err := p.Tables().GetMutableTableVersionByID(ctx, ref.OriginTableID, p.txn)
   436  		if err != nil {
   437  			return errors.Errorf("error resolving origin table ID %d: %v", ref.OriginTableID, err)
   438  		}
   439  		originTableDesc = lookup
   440  	}
   441  	if originTableDesc.Dropped() {
   442  		// The origin table is being dropped. No need to modify it further.
   443  		return nil
   444  	}
   445  
   446  	if err := removeFKForBackReferenceFromTable(originTableDesc, ref, tableDesc.TableDesc()); err != nil {
   447  		return err
   448  	}
   449  	// No job description, since this is presumably part of some larger schema change.
   450  	return p.writeSchemaChange(ctx, originTableDesc, sqlbase.InvalidMutationID, "")
   451  }
   452  
   453  // removeFKBackReferenceFromTable edits the supplied originTableDesc to
   454  // remove the foreign key constraint that corresponds to the supplied
   455  // backreference, which is a member of the supplied referencedTableDesc.
   456  func removeFKForBackReferenceFromTable(
   457  	originTableDesc *sqlbase.MutableTableDescriptor,
   458  	backref *sqlbase.ForeignKeyConstraint,
   459  	referencedTableDesc *sqlbase.TableDescriptor,
   460  ) error {
   461  	matchIdx := -1
   462  	for i, fk := range originTableDesc.OutboundFKs {
   463  		if fk.ReferencedTableID == referencedTableDesc.ID && fk.Name == backref.Name {
   464  			// We found a match! We want to delete it from the list now.
   465  			matchIdx = i
   466  			break
   467  		}
   468  	}
   469  	if matchIdx == -1 {
   470  		// There was no match: no back reference in the referenced table that
   471  		// matched the foreign key constraint that we were trying to delete.
   472  		// This really shouldn't happen...
   473  		return errors.AssertionFailedf("there was no foreign key constraint "+
   474  			"for backreference %v on table %q", backref, originTableDesc.Name)
   475  	}
   476  	// Delete our match.
   477  	originTableDesc.OutboundFKs = append(
   478  		originTableDesc.OutboundFKs[:matchIdx],
   479  		originTableDesc.OutboundFKs[matchIdx+1:]...)
   480  	return nil
   481  }
   482  
   483  // removeFKBackReference removes the FK back reference from the table that is
   484  // referenced by the input constraint.
   485  func (p *planner) removeFKBackReference(
   486  	ctx context.Context, tableDesc *sqlbase.MutableTableDescriptor, ref *sqlbase.ForeignKeyConstraint,
   487  ) error {
   488  	var referencedTableDesc *sqlbase.MutableTableDescriptor
   489  	// We don't want to lookup/edit a second copy of the same table.
   490  	if tableDesc.ID == ref.ReferencedTableID {
   491  		referencedTableDesc = tableDesc
   492  	} else {
   493  		lookup, err := p.Tables().GetMutableTableVersionByID(ctx, ref.ReferencedTableID, p.txn)
   494  		if err != nil {
   495  			return errors.Errorf("error resolving referenced table ID %d: %v", ref.ReferencedTableID, err)
   496  		}
   497  		referencedTableDesc = lookup
   498  	}
   499  	if referencedTableDesc.Dropped() {
   500  		// The referenced table is being dropped. No need to modify it further.
   501  		return nil
   502  	}
   503  
   504  	if err := removeFKBackReferenceFromTable(referencedTableDesc, ref.Name, tableDesc.TableDesc()); err != nil {
   505  		return err
   506  	}
   507  	// No job description, since this is presumably part of some larger schema change.
   508  	return p.writeSchemaChange(ctx, referencedTableDesc, sqlbase.InvalidMutationID, "")
   509  }
   510  
   511  // removeFKBackReferenceFromTable edits the supplied referencedTableDesc to
   512  // remove the foreign key backreference that corresponds to the supplied fk,
   513  // which is a member of the supplied originTableDesc.
   514  func removeFKBackReferenceFromTable(
   515  	referencedTableDesc *sqlbase.MutableTableDescriptor,
   516  	fkName string,
   517  	originTableDesc *sqlbase.TableDescriptor,
   518  ) error {
   519  	matchIdx := -1
   520  	for i, backref := range referencedTableDesc.InboundFKs {
   521  		if backref.OriginTableID == originTableDesc.ID && backref.Name == fkName {
   522  			// We found a match! We want to delete it from the list now.
   523  			matchIdx = i
   524  			break
   525  		}
   526  	}
   527  	if matchIdx == -1 {
   528  		// There was no match: no back reference in the referenced table that
   529  		// matched the foreign key constraint that we were trying to delete.
   530  		// This really shouldn't happen...
   531  		return errors.AssertionFailedf("there was no foreign key backreference "+
   532  			"for constraint %q on table %q", fkName, originTableDesc.Name)
   533  	}
   534  	// Delete our match.
   535  	referencedTableDesc.InboundFKs = append(referencedTableDesc.InboundFKs[:matchIdx], referencedTableDesc.InboundFKs[matchIdx+1:]...)
   536  	return nil
   537  }
   538  
   539  func (p *planner) removeInterleaveBackReference(
   540  	ctx context.Context, tableDesc *sqlbase.MutableTableDescriptor, idx *sqlbase.IndexDescriptor,
   541  ) error {
   542  	if len(idx.Interleave.Ancestors) == 0 {
   543  		return nil
   544  	}
   545  	ancestor := idx.Interleave.Ancestors[len(idx.Interleave.Ancestors)-1]
   546  	var t *sqlbase.MutableTableDescriptor
   547  	if ancestor.TableID == tableDesc.ID {
   548  		t = tableDesc
   549  	} else {
   550  		lookup, err := p.Tables().GetMutableTableVersionByID(ctx, ancestor.TableID, p.txn)
   551  		if err != nil {
   552  			return errors.Errorf("error resolving referenced table ID %d: %v", ancestor.TableID, err)
   553  		}
   554  		t = lookup
   555  	}
   556  	if t.Dropped() {
   557  		// The referenced table is being dropped. No need to modify it further.
   558  		return nil
   559  	}
   560  	targetIdx, err := t.FindIndexByID(ancestor.IndexID)
   561  	if err != nil {
   562  		return err
   563  	}
   564  	foundAncestor := false
   565  	for k, ref := range targetIdx.InterleavedBy {
   566  		if ref.Table == tableDesc.ID && ref.Index == idx.ID {
   567  			if foundAncestor {
   568  				return errors.AssertionFailedf(
   569  					"ancestor entry in %s for %s@%s found more than once", t.Name, tableDesc.Name, idx.Name)
   570  			}
   571  			targetIdx.InterleavedBy = append(targetIdx.InterleavedBy[:k], targetIdx.InterleavedBy[k+1:]...)
   572  			foundAncestor = true
   573  		}
   574  	}
   575  	if t != tableDesc {
   576  		// TODO (lucy): Have more consistent/informative names for dependent jobs.
   577  		return p.writeSchemaChange(
   578  			ctx, t, sqlbase.InvalidMutationID, "removing reference for interleaved table",
   579  		)
   580  	}
   581  	return nil
   582  }
   583  
   584  // removeMatchingReferences removes all refs from the provided slice that
   585  // match the provided ID, returning the modified slice.
   586  func removeMatchingReferences(
   587  	refs []sqlbase.TableDescriptor_Reference, id sqlbase.ID,
   588  ) []sqlbase.TableDescriptor_Reference {
   589  	updatedRefs := refs[:0]
   590  	for _, ref := range refs {
   591  		if ref.ID != id {
   592  			updatedRefs = append(updatedRefs, ref)
   593  		}
   594  	}
   595  	return updatedRefs
   596  }
   597  
   598  func (p *planner) removeTableComments(
   599  	ctx context.Context, tableDesc *sqlbase.MutableTableDescriptor,
   600  ) error {
   601  	_, err := p.ExtendedEvalContext().ExecCfg.InternalExecutor.ExecEx(
   602  		ctx,
   603  		"delete-table-comments",
   604  		p.txn,
   605  		sqlbase.InternalExecutorSessionDataOverride{User: security.RootUser},
   606  		"DELETE FROM system.comments WHERE object_id=$1",
   607  		tableDesc.ID)
   608  	if err != nil {
   609  		return err
   610  	}
   611  	return err
   612  }