github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/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  	"fmt"
    16  	"math"
    17  
    18  	"github.com/cockroachdb/cockroach/pkg/keys"
    19  	"github.com/cockroachdb/cockroach/pkg/kv"
    20  	"github.com/cockroachdb/cockroach/pkg/roachpb"
    21  	"github.com/cockroachdb/cockroach/pkg/sql/catalog/resolver"
    22  	"github.com/cockroachdb/cockroach/pkg/sql/parser"
    23  	"github.com/cockroachdb/cockroach/pkg/sql/pgwire/pgcode"
    24  	"github.com/cockroachdb/cockroach/pkg/sql/pgwire/pgerror"
    25  	"github.com/cockroachdb/cockroach/pkg/sql/privilege"
    26  	"github.com/cockroachdb/cockroach/pkg/sql/sem/builtins"
    27  	"github.com/cockroachdb/cockroach/pkg/sql/sem/tree"
    28  	"github.com/cockroachdb/cockroach/pkg/sql/sessiondata"
    29  	"github.com/cockroachdb/cockroach/pkg/sql/sqlbase"
    30  	"github.com/cockroachdb/cockroach/pkg/util/errorutil/unimplemented"
    31  	"github.com/cockroachdb/errors"
    32  )
    33  
    34  // IncrementSequence implements the tree.SequenceOperators interface.
    35  func (p *planner) IncrementSequence(ctx context.Context, seqName *tree.TableName) (int64, error) {
    36  	if p.EvalContext().TxnReadOnly {
    37  		return 0, readOnlyError("nextval()")
    38  	}
    39  
    40  	descriptor, err := resolver.ResolveExistingTableObject(ctx, p, seqName, tree.ObjectLookupFlagsWithRequired(), resolver.ResolveRequireSequenceDesc)
    41  	if err != nil {
    42  		return 0, err
    43  	}
    44  	if err := p.CheckPrivilege(ctx, descriptor, privilege.UPDATE); err != nil {
    45  		return 0, err
    46  	}
    47  
    48  	seqOpts := descriptor.SequenceOpts
    49  	var val int64
    50  	if seqOpts.Virtual {
    51  		rowid := builtins.GenerateUniqueInt(p.EvalContext().NodeID.SQLInstanceID())
    52  		val = int64(rowid)
    53  	} else {
    54  		seqValueKey := p.ExecCfg().Codec.SequenceKey(uint32(descriptor.ID))
    55  		val, err = kv.IncrementValRetryable(
    56  			ctx, p.txn.DB(), seqValueKey, seqOpts.Increment)
    57  		if err != nil {
    58  			if errors.HasType(err, (*roachpb.IntegerOverflowError)(nil)) {
    59  				return 0, boundsExceededError(descriptor)
    60  			}
    61  			return 0, err
    62  		}
    63  		if val > seqOpts.MaxValue || val < seqOpts.MinValue {
    64  			return 0, boundsExceededError(descriptor)
    65  		}
    66  	}
    67  
    68  	p.ExtendedEvalContext().SessionMutator.RecordLatestSequenceVal(uint32(descriptor.ID), val)
    69  
    70  	return val, nil
    71  }
    72  
    73  func boundsExceededError(descriptor *sqlbase.ImmutableTableDescriptor) error {
    74  	seqOpts := descriptor.SequenceOpts
    75  	isAscending := seqOpts.Increment > 0
    76  
    77  	var word string
    78  	var value int64
    79  	if isAscending {
    80  		word = "maximum"
    81  		value = seqOpts.MaxValue
    82  	} else {
    83  		word = "minimum"
    84  		value = seqOpts.MinValue
    85  	}
    86  	return pgerror.Newf(
    87  		pgcode.SequenceGeneratorLimitExceeded,
    88  		`reached %s value of sequence %q (%d)`, word,
    89  		tree.ErrString((*tree.Name)(&descriptor.Name)), value)
    90  }
    91  
    92  // GetLatestValueInSessionForSequence implements the tree.SequenceOperators interface.
    93  func (p *planner) GetLatestValueInSessionForSequence(
    94  	ctx context.Context, seqName *tree.TableName,
    95  ) (int64, error) {
    96  	descriptor, err := resolver.ResolveExistingTableObject(ctx, p, seqName, tree.ObjectLookupFlagsWithRequired(), resolver.ResolveRequireSequenceDesc)
    97  	if err != nil {
    98  		return 0, err
    99  	}
   100  
   101  	val, ok := p.SessionData().SequenceState.GetLastValueByID(uint32(descriptor.ID))
   102  	if !ok {
   103  		return 0, pgerror.Newf(
   104  			pgcode.ObjectNotInPrerequisiteState,
   105  			`currval of sequence %q is not yet defined in this session`, tree.ErrString(seqName))
   106  	}
   107  
   108  	return val, nil
   109  }
   110  
   111  // SetSequenceValue implements the tree.SequenceOperators interface.
   112  func (p *planner) SetSequenceValue(
   113  	ctx context.Context, seqName *tree.TableName, newVal int64, isCalled bool,
   114  ) error {
   115  	if p.EvalContext().TxnReadOnly {
   116  		return readOnlyError("setval()")
   117  	}
   118  
   119  	descriptor, err := resolver.ResolveExistingTableObject(ctx, p, seqName, tree.ObjectLookupFlagsWithRequired(), resolver.ResolveRequireSequenceDesc)
   120  	if err != nil {
   121  		return err
   122  	}
   123  	if err := p.CheckPrivilege(ctx, descriptor, privilege.UPDATE); err != nil {
   124  		return err
   125  	}
   126  
   127  	if descriptor.SequenceOpts.Virtual {
   128  		// TODO(knz): we currently return an error here, but if/when
   129  		// CockroachDB grows to automatically make sequences virtual when
   130  		// clients don't expect it, we may need to make this a no-op
   131  		// instead.
   132  		return pgerror.Newf(
   133  			pgcode.ObjectNotInPrerequisiteState,
   134  			`cannot set the value of virtual sequence %q`, tree.ErrString(seqName))
   135  	}
   136  
   137  	seqValueKey, newVal, err := MakeSequenceKeyVal(p.ExecCfg().Codec, descriptor.TableDesc(), newVal, isCalled)
   138  	if err != nil {
   139  		return err
   140  	}
   141  
   142  	// TODO(vilterp): not supposed to mix usage of Inc and Put on a key,
   143  	// according to comments on Inc operation. Switch to Inc if `desired-current`
   144  	// overflows correctly.
   145  	return p.txn.Put(ctx, seqValueKey, newVal)
   146  }
   147  
   148  // MakeSequenceKeyVal returns the key and value of a sequence being set
   149  // with newVal.
   150  func MakeSequenceKeyVal(
   151  	codec keys.SQLCodec, sequence *TableDescriptor, newVal int64, isCalled bool,
   152  ) ([]byte, int64, error) {
   153  	opts := sequence.SequenceOpts
   154  	if newVal > opts.MaxValue || newVal < opts.MinValue {
   155  		return nil, 0, pgerror.Newf(
   156  			pgcode.NumericValueOutOfRange,
   157  			`value %d is out of bounds for sequence "%s" (%d..%d)`,
   158  			newVal, sequence.Name, opts.MinValue, opts.MaxValue,
   159  		)
   160  	}
   161  	if !isCalled {
   162  		newVal = newVal - sequence.SequenceOpts.Increment
   163  	}
   164  
   165  	seqValueKey := codec.SequenceKey(uint32(sequence.ID))
   166  	return seqValueKey, newVal, nil
   167  }
   168  
   169  // GetSequenceValue returns the current value of the sequence.
   170  func (p *planner) GetSequenceValue(
   171  	ctx context.Context, codec keys.SQLCodec, desc *sqlbase.ImmutableTableDescriptor,
   172  ) (int64, error) {
   173  	if desc.SequenceOpts == nil {
   174  		return 0, errors.New("descriptor is not a sequence")
   175  	}
   176  	keyValue, err := p.txn.Get(ctx, codec.SequenceKey(uint32(desc.ID)))
   177  	if err != nil {
   178  		return 0, err
   179  	}
   180  	return keyValue.ValueInt(), nil
   181  }
   182  
   183  func readOnlyError(s string) error {
   184  	return pgerror.Newf(pgcode.ReadOnlySQLTransaction,
   185  		"cannot execute %s in a read-only transaction", s)
   186  }
   187  
   188  // assignSequenceOptions moves options from the AST node to the sequence options descriptor,
   189  // starting with defaults and overriding them with user-provided options.
   190  func assignSequenceOptions(
   191  	opts *sqlbase.TableDescriptor_SequenceOpts,
   192  	optsNode tree.SequenceOptions,
   193  	setDefaults bool,
   194  	params *runParams,
   195  	sequenceID sqlbase.ID,
   196  ) error {
   197  	// All other defaults are dependent on the value of increment,
   198  	// i.e. whether the sequence is ascending or descending.
   199  	for _, option := range optsNode {
   200  		if option.Name == tree.SeqOptIncrement {
   201  			opts.Increment = *option.IntVal
   202  		}
   203  	}
   204  	if opts.Increment == 0 {
   205  		return pgerror.New(
   206  			pgcode.InvalidParameterValue, "INCREMENT must not be zero")
   207  	}
   208  	isAscending := opts.Increment > 0
   209  
   210  	// Set increment-dependent defaults.
   211  	if setDefaults {
   212  		if isAscending {
   213  			opts.MinValue = 1
   214  			opts.MaxValue = math.MaxInt64
   215  			opts.Start = opts.MinValue
   216  		} else {
   217  			opts.MinValue = math.MinInt64
   218  			opts.MaxValue = -1
   219  			opts.Start = opts.MaxValue
   220  		}
   221  	}
   222  
   223  	// Fill in all other options.
   224  	optionsSeen := map[string]bool{}
   225  	for _, option := range optsNode {
   226  		// Error on duplicate options.
   227  		_, seenBefore := optionsSeen[option.Name]
   228  		if seenBefore {
   229  			return pgerror.New(pgcode.Syntax, "conflicting or redundant options")
   230  		}
   231  		optionsSeen[option.Name] = true
   232  
   233  		switch option.Name {
   234  		case tree.SeqOptCycle:
   235  			return unimplemented.NewWithIssue(20961,
   236  				"CYCLE option is not supported")
   237  		case tree.SeqOptNoCycle:
   238  			// Do nothing; this is the default.
   239  		case tree.SeqOptCache:
   240  			v := *option.IntVal
   241  			switch {
   242  			case v < 1:
   243  				return pgerror.Newf(pgcode.InvalidParameterValue,
   244  					"CACHE (%d) must be greater than zero", v)
   245  			case v == 1:
   246  				// Do nothing; this is the default.
   247  			case v > 1:
   248  				return unimplemented.NewWithIssuef(32567,
   249  					"CACHE values larger than 1 are not supported, found %d", v)
   250  			}
   251  		case tree.SeqOptIncrement:
   252  			// Do nothing; this has already been set.
   253  		case tree.SeqOptMinValue:
   254  			// A value of nil represents the user explicitly saying `NO MINVALUE`.
   255  			if option.IntVal != nil {
   256  				opts.MinValue = *option.IntVal
   257  			}
   258  		case tree.SeqOptMaxValue:
   259  			// A value of nil represents the user explicitly saying `NO MAXVALUE`.
   260  			if option.IntVal != nil {
   261  				opts.MaxValue = *option.IntVal
   262  			}
   263  		case tree.SeqOptStart:
   264  			opts.Start = *option.IntVal
   265  		case tree.SeqOptVirtual:
   266  			opts.Virtual = true
   267  		case tree.SeqOptOwnedBy:
   268  			if params == nil {
   269  				return pgerror.Newf(pgcode.Internal,
   270  					"Trying to add/remove Sequence Owner without access to context")
   271  			}
   272  			// The owner is being removed
   273  			if option.ColumnItemVal == nil {
   274  				if err := removeSequenceOwnerIfExists(params.ctx, params.p, sequenceID, opts); err != nil {
   275  					return err
   276  				}
   277  			} else {
   278  				// The owner is being added/modified
   279  				tableDesc, col, err := resolveColumnItemToDescriptors(
   280  					params.ctx, params.p, option.ColumnItemVal,
   281  				)
   282  				if err != nil {
   283  					return err
   284  				}
   285  				// We only want to trigger schema changes if the owner is not what we
   286  				// want it to be.
   287  				if opts.SequenceOwner.OwnerTableID != tableDesc.ID ||
   288  					opts.SequenceOwner.OwnerColumnID != col.ID {
   289  					if err := removeSequenceOwnerIfExists(params.ctx, params.p, sequenceID, opts); err != nil {
   290  						return err
   291  					}
   292  					err := addSequenceOwner(params.ctx, params.p, tableDesc, col, sequenceID, opts)
   293  					if err != nil {
   294  						return err
   295  					}
   296  				}
   297  			}
   298  		}
   299  	}
   300  
   301  	// If start option not specified, set it to MinValue (for ascending sequences)
   302  	// or MaxValue (for descending sequences).
   303  	if _, startSeen := optionsSeen[tree.SeqOptStart]; !startSeen {
   304  		if opts.Increment > 0 {
   305  			opts.Start = opts.MinValue
   306  		} else {
   307  			opts.Start = opts.MaxValue
   308  		}
   309  	}
   310  
   311  	if opts.Start > opts.MaxValue {
   312  		return pgerror.Newf(
   313  			pgcode.InvalidParameterValue,
   314  			"START value (%d) cannot be greater than MAXVALUE (%d)", opts.Start, opts.MaxValue)
   315  	}
   316  	if opts.Start < opts.MinValue {
   317  		return pgerror.Newf(
   318  			pgcode.InvalidParameterValue,
   319  			"START value (%d) cannot be less than MINVALUE (%d)", opts.Start, opts.MinValue)
   320  	}
   321  
   322  	return nil
   323  }
   324  
   325  func removeSequenceOwnerIfExists(
   326  	ctx context.Context,
   327  	p *planner,
   328  	sequenceID sqlbase.ID,
   329  	opts *sqlbase.TableDescriptor_SequenceOpts,
   330  ) error {
   331  	if opts.SequenceOwner.Equal(sqlbase.TableDescriptor_SequenceOpts_SequenceOwner{}) {
   332  		return nil
   333  	}
   334  	tableDesc, err := p.Tables().GetMutableTableVersionByID(ctx, opts.SequenceOwner.OwnerTableID, p.txn)
   335  	if err != nil {
   336  		return err
   337  	}
   338  	col, err := tableDesc.FindColumnByID(opts.SequenceOwner.OwnerColumnID)
   339  	if err != nil {
   340  		return err
   341  	}
   342  	// Find an item in colDesc.OwnsSequenceIds which references SequenceID.
   343  	refIdx := -1
   344  	for i, id := range col.OwnsSequenceIds {
   345  		if id == sequenceID {
   346  			refIdx = i
   347  		}
   348  	}
   349  	if refIdx == -1 {
   350  		return errors.AssertionFailedf("couldn't find reference from column to this sequence")
   351  	}
   352  	col.OwnsSequenceIds = append(col.OwnsSequenceIds[:refIdx], col.OwnsSequenceIds[refIdx+1:]...)
   353  	// TODO (lucy): Have more consistent/informative names for dependent jobs.
   354  	if err := p.writeSchemaChange(
   355  		ctx, tableDesc, sqlbase.InvalidMutationID, "removing sequence owner",
   356  	); err != nil {
   357  		return err
   358  	}
   359  	// Reset the SequenceOwner to empty
   360  	opts.SequenceOwner.Reset()
   361  	return nil
   362  }
   363  
   364  func resolveColumnItemToDescriptors(
   365  	ctx context.Context, p *planner, columnItem *tree.ColumnItem,
   366  ) (*MutableTableDescriptor, *sqlbase.ColumnDescriptor, error) {
   367  	var tableName tree.TableName
   368  	if columnItem.TableName != nil {
   369  		tableName = columnItem.TableName.ToTableName()
   370  	}
   371  
   372  	tableDesc, err := p.ResolveMutableTableDescriptor(ctx, &tableName, true /* required */, resolver.ResolveRequireTableDesc)
   373  	if err != nil {
   374  		return nil, nil, err
   375  	}
   376  	col, _, err := tableDesc.FindColumnByName(columnItem.ColumnName)
   377  	if err != nil {
   378  		return nil, nil, err
   379  	}
   380  	return tableDesc, col, nil
   381  }
   382  
   383  func addSequenceOwner(
   384  	ctx context.Context,
   385  	p *planner,
   386  	tableDesc *MutableTableDescriptor,
   387  	col *sqlbase.ColumnDescriptor,
   388  	sequenceID sqlbase.ID,
   389  	opts *sqlbase.TableDescriptor_SequenceOpts,
   390  ) error {
   391  	col.OwnsSequenceIds = append(col.OwnsSequenceIds, sequenceID)
   392  
   393  	opts.SequenceOwner.OwnerColumnID = col.ID
   394  	opts.SequenceOwner.OwnerTableID = tableDesc.GetID()
   395  	// TODO (lucy): Have more consistent/informative names for dependent jobs.
   396  	return p.writeSchemaChange(
   397  		ctx, tableDesc, sqlbase.InvalidMutationID, "adding sequence owner",
   398  	)
   399  }
   400  
   401  // maybeAddSequenceDependencies adds references between the column and sequence descriptors,
   402  // if the column has a DEFAULT expression that uses one or more sequences. (Usually just one,
   403  // e.g. `DEFAULT nextval('my_sequence')`.
   404  // The passed-in column descriptor is mutated, and the modified sequence descriptors are returned.
   405  func maybeAddSequenceDependencies(
   406  	ctx context.Context,
   407  	sc resolver.SchemaResolver,
   408  	tableDesc *sqlbase.MutableTableDescriptor,
   409  	col *sqlbase.ColumnDescriptor,
   410  	expr tree.TypedExpr,
   411  	backrefs map[sqlbase.ID]*sqlbase.MutableTableDescriptor,
   412  ) ([]*MutableTableDescriptor, error) {
   413  	seqNames, err := getUsedSequenceNames(expr)
   414  	if err != nil {
   415  		return nil, err
   416  	}
   417  	var seqDescs []*MutableTableDescriptor
   418  	for _, seqName := range seqNames {
   419  		parsedSeqName, err := parser.ParseTableName(seqName)
   420  		if err != nil {
   421  			return nil, err
   422  		}
   423  		tn := parsedSeqName.ToTableName()
   424  
   425  		var seqDesc *MutableTableDescriptor
   426  		p, ok := sc.(*planner)
   427  		if ok {
   428  			seqDesc, err = p.ResolveMutableTableDescriptor(ctx, &tn, true /*required*/, resolver.ResolveRequireSequenceDesc)
   429  			if err != nil {
   430  				return nil, err
   431  			}
   432  		} else {
   433  			// This is only executed via IMPORT which uses its own resolver.
   434  			seqDesc, err = resolver.ResolveMutableExistingTableObject(ctx, sc, &tn, true /*required*/, resolver.ResolveRequireSequenceDesc)
   435  			if err != nil {
   436  				return nil, err
   437  			}
   438  		}
   439  		// If we had already modified this Sequence as part of this transaction,
   440  		// we only want to modify a single instance of it instead of overwriting it.
   441  		// So replace seqDesc with the descriptor that was previously modified.
   442  		if prev, ok := backrefs[seqDesc.ID]; ok {
   443  			seqDesc = prev
   444  		}
   445  		col.UsesSequenceIds = append(col.UsesSequenceIds, seqDesc.ID)
   446  		// Add reference from sequence descriptor to column.
   447  		refIdx := -1
   448  		for i, reference := range seqDesc.DependedOnBy {
   449  			if reference.ID == tableDesc.ID {
   450  				refIdx = i
   451  			}
   452  		}
   453  		if refIdx == -1 {
   454  			seqDesc.DependedOnBy = append(seqDesc.DependedOnBy, sqlbase.TableDescriptor_Reference{
   455  				ID:        tableDesc.ID,
   456  				ColumnIDs: []sqlbase.ColumnID{col.ID},
   457  			})
   458  		} else {
   459  			seqDesc.DependedOnBy[refIdx].ColumnIDs = append(seqDesc.DependedOnBy[refIdx].ColumnIDs, col.ID)
   460  		}
   461  		seqDescs = append(seqDescs, seqDesc)
   462  	}
   463  	return seqDescs, nil
   464  }
   465  
   466  // dropSequencesOwnedByCol drops all the sequences from col.OwnsSequenceIDs.
   467  // Called when the respective column (or the whole table) is being dropped.
   468  func (p *planner) dropSequencesOwnedByCol(
   469  	ctx context.Context, col *sqlbase.ColumnDescriptor,
   470  ) error {
   471  	for _, sequenceID := range col.OwnsSequenceIds {
   472  		seqDesc, err := p.Tables().GetMutableTableVersionByID(ctx, sequenceID, p.txn)
   473  		if err != nil {
   474  			return err
   475  		}
   476  		jobDesc := fmt.Sprintf("removing sequence %q dependent on column %q which is being dropped",
   477  			seqDesc.Name, col.ColName())
   478  		if err := p.dropSequenceImpl(
   479  			ctx, seqDesc, true /* queueJob */, jobDesc, tree.DropRestrict,
   480  		); err != nil {
   481  			return err
   482  		}
   483  	}
   484  	return nil
   485  }
   486  
   487  // removeSequenceDependencies:
   488  //   - removes the reference from the column descriptor to the sequence descriptor.
   489  //   - removes the reference from the sequence descriptor to the column descriptor.
   490  //   - writes the sequence descriptor and notifies a schema change.
   491  // The column descriptor is mutated but not saved to persistent storage; the caller must save it.
   492  func (p *planner) removeSequenceDependencies(
   493  	ctx context.Context, tableDesc *sqlbase.MutableTableDescriptor, col *sqlbase.ColumnDescriptor,
   494  ) error {
   495  	for _, sequenceID := range col.UsesSequenceIds {
   496  		// Get the sequence descriptor so we can remove the reference from it.
   497  		seqDesc, err := p.Tables().GetMutableTableVersionByID(ctx, sequenceID, p.txn)
   498  		if err != nil {
   499  			return err
   500  		}
   501  		// Find the item in seqDesc.DependedOnBy which references tableDesc and col.
   502  		refTableIdx := -1
   503  		refColIdx := -1
   504  	found:
   505  		for i, reference := range seqDesc.DependedOnBy {
   506  			if reference.ID == tableDesc.ID {
   507  				refTableIdx = i
   508  				for j, colRefID := range seqDesc.DependedOnBy[i].ColumnIDs {
   509  					if colRefID == col.ID {
   510  						refColIdx = j
   511  						break found
   512  					}
   513  					// Before #40852, columnIDs stored in the SeqDesc were 0 as they hadn't
   514  					// been allocated then. The 0 check prevents older descs from breaking.
   515  					// Do not break though, as we still want to search in case the actual ID
   516  					// exists.
   517  					if colRefID == 0 {
   518  						refColIdx = j
   519  					}
   520  				}
   521  			}
   522  		}
   523  		if refColIdx == -1 {
   524  			return errors.AssertionFailedf("couldn't find reference from sequence to this column")
   525  		}
   526  		// Remove the column ID from the sequence descriptors list of things that
   527  		// depend on it. If the column was the only column that depended on the
   528  		// sequence, remove the table reference from the sequence as well.
   529  		seqDesc.DependedOnBy[refTableIdx].ColumnIDs = append(
   530  			seqDesc.DependedOnBy[refTableIdx].ColumnIDs[:refColIdx],
   531  			seqDesc.DependedOnBy[refTableIdx].ColumnIDs[refColIdx+1:]...)
   532  
   533  		if len(seqDesc.DependedOnBy[refTableIdx].ColumnIDs) == 0 {
   534  			seqDesc.DependedOnBy = append(
   535  				seqDesc.DependedOnBy[:refTableIdx],
   536  				seqDesc.DependedOnBy[refTableIdx+1:]...)
   537  		}
   538  
   539  		jobDesc := fmt.Sprintf("removing sequence %q dependent on column %q which is being dropped",
   540  			seqDesc.Name, col.ColName())
   541  		if err := p.writeSchemaChange(
   542  			ctx, seqDesc, sqlbase.InvalidMutationID, jobDesc,
   543  		); err != nil {
   544  			return err
   545  		}
   546  	}
   547  	// Remove the reference from the column descriptor to the sequence descriptor.
   548  	col.UsesSequenceIds = []sqlbase.ID{}
   549  	return nil
   550  }
   551  
   552  // getUsedSequenceNames returns the name of the sequence passed to
   553  // a call to nextval in the given expression, or nil if there is
   554  // no call to nextval.
   555  // e.g. nextval('foo') => "foo"; <some other expression> => nil
   556  func getUsedSequenceNames(defaultExpr tree.TypedExpr) ([]string, error) {
   557  	searchPath := sessiondata.SearchPath{}
   558  	var names []string
   559  	_, err := tree.SimpleVisit(
   560  		defaultExpr,
   561  		func(expr tree.Expr) (recurse bool, newExpr tree.Expr, err error) {
   562  			switch t := expr.(type) {
   563  			case *tree.FuncExpr:
   564  				def, err := t.Func.Resolve(searchPath)
   565  				if err != nil {
   566  					return false, expr, err
   567  				}
   568  				if def.Name == "nextval" {
   569  					arg := t.Exprs[0]
   570  					switch a := arg.(type) {
   571  					case *tree.DString:
   572  						names = append(names, string(*a))
   573  					}
   574  				}
   575  			}
   576  			return true, expr, nil
   577  		},
   578  	)
   579  	if err != nil {
   580  		return nil, err
   581  	}
   582  	return names, nil
   583  }