github.com/cockroachdb/cockroachdb-parser@v0.23.3-0.20240213214944-911057d40c9a/pkg/sql/sem/tree/create_routine.go (about)

     1  // Copyright 2022 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  	"context"
    15  	"strings"
    16  
    17  	"github.com/cockroachdb/cockroachdb-parser/pkg/sql/pgwire/pgcode"
    18  	"github.com/cockroachdb/cockroachdb-parser/pkg/sql/pgwire/pgerror"
    19  	"github.com/cockroachdb/cockroachdb-parser/pkg/sql/types"
    20  	"github.com/cockroachdb/errors"
    21  )
    22  
    23  // ErrConflictingRoutineOption indicates that there are conflicting or
    24  // redundant function options from user input to either create or alter a
    25  // function.
    26  var ErrConflictingRoutineOption = pgerror.New(pgcode.Syntax, "conflicting or redundant options")
    27  
    28  // RoutineName represent a function name in a UDF relevant statement, either
    29  // DDL or DML statement. Similar to TableName, it is constructed for incoming
    30  // SQL queries from an UnresolvedObjectName.
    31  type RoutineName struct {
    32  	objName
    33  }
    34  
    35  // MakeRoutineNameFromPrefix returns a RoutineName with the given prefix and
    36  // function name.
    37  func MakeRoutineNameFromPrefix(prefix ObjectNamePrefix, object Name) RoutineName {
    38  	return RoutineName{objName{
    39  		ObjectName:       object,
    40  		ObjectNamePrefix: prefix,
    41  	}}
    42  }
    43  
    44  // MakeQualifiedRoutineName constructs a RoutineName with the given db and
    45  // schema name as prefix.
    46  func MakeQualifiedRoutineName(db string, sc string, fn string) RoutineName {
    47  	return MakeRoutineNameFromPrefix(
    48  		ObjectNamePrefix{
    49  			CatalogName:     Name(db),
    50  			ExplicitCatalog: true,
    51  			SchemaName:      Name(sc),
    52  			ExplicitSchema:  true,
    53  		}, Name(fn),
    54  	)
    55  }
    56  
    57  // Format implements the NodeFormatter interface.
    58  func (f *RoutineName) Format(ctx *FmtCtx) {
    59  	f.ObjectNamePrefix.Format(ctx)
    60  	if f.ExplicitSchema || ctx.alwaysFormatTablePrefix() {
    61  		ctx.WriteByte('.')
    62  	}
    63  	ctx.FormatNode(&f.ObjectName)
    64  }
    65  
    66  func (f *RoutineName) String() string { return AsString(f) }
    67  
    68  // FQString renders the function name in full, not omitting the prefix
    69  // schema and catalog names. Suitable for logging, etc.
    70  func (f *RoutineName) FQString() string {
    71  	ctx := NewFmtCtx(FmtSimple)
    72  	ctx.FormatNode(&f.CatalogName)
    73  	ctx.WriteByte('.')
    74  	ctx.FormatNode(&f.SchemaName)
    75  	ctx.WriteByte('.')
    76  	ctx.FormatNode(&f.ObjectName)
    77  	return ctx.CloseAndGetString()
    78  }
    79  
    80  func (f *RoutineName) objectName() {}
    81  
    82  // CreateRoutine represents a CREATE FUNCTION or CREATE PROCEDURE statement.
    83  type CreateRoutine struct {
    84  	IsProcedure bool
    85  	Replace     bool
    86  	Name        RoutineName
    87  	Params      RoutineParams
    88  	ReturnType  RoutineReturnType
    89  	Options     RoutineOptions
    90  	RoutineBody *RoutineBody
    91  	// BodyStatements is not assigned during initial parsing of user input. It's
    92  	// assigned during opt builder for logging purpose at the moment. It stores
    93  	// all parsed AST nodes of body statements with all expression in original
    94  	// format. That is sequence names and type name in expressions are not
    95  	// rewritten with OIDs.
    96  	BodyStatements Statements
    97  	// BodyAnnotations is not assigned during initial parsing of user input. It's
    98  	// assigned by the opt builder when the optimizer parses the body statements.
    99  	BodyAnnotations []*Annotations
   100  }
   101  
   102  // Format implements the NodeFormatter interface.
   103  func (node *CreateRoutine) Format(ctx *FmtCtx) {
   104  	ctx.WriteString("CREATE ")
   105  	if node.Replace {
   106  		ctx.WriteString("OR REPLACE ")
   107  	}
   108  	if node.IsProcedure {
   109  		ctx.WriteString("PROCEDURE ")
   110  	} else {
   111  		ctx.WriteString("FUNCTION ")
   112  	}
   113  	ctx.FormatNode(&node.Name)
   114  	ctx.WriteByte('(')
   115  	ctx.FormatNode(node.Params)
   116  	ctx.WriteString(")\n\t")
   117  	if !node.IsProcedure {
   118  		ctx.WriteString("RETURNS ")
   119  		if node.ReturnType.SetOf {
   120  			ctx.WriteString("SETOF ")
   121  		}
   122  		ctx.FormatTypeReference(node.ReturnType.Type)
   123  		ctx.WriteString("\n\t")
   124  	}
   125  	var funcBody RoutineBodyStr
   126  	for _, option := range node.Options {
   127  		switch t := option.(type) {
   128  		case RoutineBodyStr:
   129  			funcBody = t
   130  			continue
   131  		case RoutineLeakproof, RoutineVolatility, RoutineNullInputBehavior:
   132  			if node.IsProcedure {
   133  				continue
   134  			}
   135  		}
   136  		ctx.FormatNode(option)
   137  		ctx.WriteString("\n\t")
   138  	}
   139  
   140  	if ctx.HasFlags(FmtMarkRedactionNode) {
   141  		ctx.WriteString("AS ")
   142  		ctx.WriteString("$$")
   143  		for i, stmt := range node.BodyStatements {
   144  			if i > 0 {
   145  				ctx.WriteByte(' ')
   146  			}
   147  			oldAnn := ctx.ann
   148  			ctx.ann = node.BodyAnnotations[i]
   149  			ctx.FormatNode(stmt)
   150  			ctx.WriteByte(';')
   151  			ctx.ann = oldAnn
   152  		}
   153  		ctx.WriteString("$$")
   154  	} else if node.RoutineBody != nil {
   155  		ctx.WriteString("BEGIN ATOMIC ")
   156  		for _, stmt := range node.RoutineBody.Stmts {
   157  			ctx.FormatNode(stmt)
   158  			ctx.WriteString("; ")
   159  		}
   160  		ctx.WriteString("END")
   161  	} else {
   162  		ctx.FormatNode(funcBody)
   163  	}
   164  }
   165  
   166  // RoutineBody represent a list of statements in a UDF body.
   167  type RoutineBody struct {
   168  	// Stmts is populated during parsing. Unlike BodyStatements, we don't need
   169  	// to create separate Annotations for each statement.
   170  	Stmts Statements
   171  }
   172  
   173  // RoutineReturn represent a RETURN statement in a UDF body.
   174  type RoutineReturn struct {
   175  	ReturnVal Expr
   176  }
   177  
   178  // Format implements the NodeFormatter interface.
   179  func (node *RoutineReturn) Format(ctx *FmtCtx) {
   180  	ctx.WriteString("RETURN ")
   181  	ctx.FormatNode(node.ReturnVal)
   182  }
   183  
   184  // RoutineOptions represent a list of routine options.
   185  type RoutineOptions []RoutineOption
   186  
   187  // RoutineOption is an interface representing UDF properties.
   188  type RoutineOption interface {
   189  	routineOption()
   190  	NodeFormatter
   191  }
   192  
   193  func (RoutineNullInputBehavior) routineOption() {}
   194  func (RoutineVolatility) routineOption()        {}
   195  func (RoutineLeakproof) routineOption()         {}
   196  func (RoutineBodyStr) routineOption()           {}
   197  func (RoutineLanguage) routineOption()          {}
   198  
   199  // RoutineNullInputBehavior represent the UDF property on null parameters.
   200  type RoutineNullInputBehavior int
   201  
   202  const (
   203  	// RoutineCalledOnNullInput indicates that the routine will be given the
   204  	// chance to execute when presented with NULL input. This is the default if
   205  	// no null input behavior is specified.
   206  	RoutineCalledOnNullInput RoutineNullInputBehavior = iota
   207  	// RoutineReturnsNullOnNullInput indicates that the routine will result in
   208  	// NULL given any NULL parameter.
   209  	RoutineReturnsNullOnNullInput
   210  	// RoutineStrict is the same as RoutineReturnsNullOnNullInput
   211  	RoutineStrict
   212  )
   213  
   214  // Format implements the NodeFormatter interface.
   215  func (node RoutineNullInputBehavior) Format(ctx *FmtCtx) {
   216  	switch node {
   217  	case RoutineCalledOnNullInput:
   218  		ctx.WriteString("CALLED ON NULL INPUT")
   219  	case RoutineReturnsNullOnNullInput:
   220  		ctx.WriteString("RETURNS NULL ON NULL INPUT")
   221  	case RoutineStrict:
   222  		ctx.WriteString("STRICT")
   223  	default:
   224  		panic(pgerror.New(pgcode.InvalidParameterValue, "Unknown routine option"))
   225  	}
   226  }
   227  
   228  // RoutineVolatility represent UDF volatility property.
   229  type RoutineVolatility int
   230  
   231  const (
   232  	// RoutineVolatile represents volatility.Volatile. This is the default
   233  	// volatility if none is provided.
   234  	RoutineVolatile RoutineVolatility = iota
   235  	// RoutineImmutable represents volatility.Immutable.
   236  	RoutineImmutable
   237  	// RoutineStable represents volatility.Stable.
   238  	RoutineStable
   239  )
   240  
   241  // Format implements the NodeFormatter interface.
   242  func (node RoutineVolatility) Format(ctx *FmtCtx) {
   243  	switch node {
   244  	case RoutineVolatile:
   245  		ctx.WriteString("VOLATILE")
   246  	case RoutineImmutable:
   247  		ctx.WriteString("IMMUTABLE")
   248  	case RoutineStable:
   249  		ctx.WriteString("STABLE")
   250  	default:
   251  		panic(pgerror.New(pgcode.InvalidParameterValue, "unknown routine option"))
   252  	}
   253  }
   254  
   255  // RoutineLeakproof indicates whether a function is leakproof or not. The
   256  // default is NOT LEAKPROOF if no leakproof option is provided. LEAKPROOF can
   257  // only be used with the IMMUTABLE volatility because we currently conflated
   258  // LEAKPROOF as a volatility equal to IMMUTABLE+LEAKPROOF. Postgres allows
   259  // STABLE+LEAKPROOF functions.
   260  type RoutineLeakproof bool
   261  
   262  // Format implements the NodeFormatter interface.
   263  func (node RoutineLeakproof) Format(ctx *FmtCtx) {
   264  	if !node {
   265  		ctx.WriteString("NOT ")
   266  	}
   267  	ctx.WriteString("LEAKPROOF")
   268  }
   269  
   270  // RoutineLanguage indicates the language of the statements in the routine body.
   271  type RoutineLanguage string
   272  
   273  const (
   274  	// RoutineLangUnknown represents an unknown language.
   275  	RoutineLangUnknown RoutineLanguage = "unknown"
   276  	// RoutineLangSQL represents SQL language.
   277  	RoutineLangSQL RoutineLanguage = "SQL"
   278  	// RoutineLangPLpgSQL represents the PL/pgSQL procedural language.
   279  	RoutineLangPLpgSQL RoutineLanguage = "plpgsql"
   280  	// RoutineLangC represents the C language.
   281  	RoutineLangC RoutineLanguage = "C"
   282  )
   283  
   284  // Format implements the NodeFormatter interface.
   285  func (node RoutineLanguage) Format(ctx *FmtCtx) {
   286  	ctx.WriteString("LANGUAGE ")
   287  	ctx.WriteString(string(node))
   288  }
   289  
   290  // AsRoutineLanguage converts a string to a RoutineLanguage if applicable.
   291  // No error is returned if string does not represent a valid UDF language;
   292  // unknown languages result in an error later.
   293  func AsRoutineLanguage(lang string) (RoutineLanguage, error) {
   294  	switch strings.ToLower(lang) {
   295  	case "sql":
   296  		return RoutineLangSQL, nil
   297  	case "plpgsql":
   298  		return RoutineLangPLpgSQL, nil
   299  	case "c":
   300  		return RoutineLangC, nil
   301  	}
   302  	return RoutineLanguage(lang), nil
   303  }
   304  
   305  // RoutineBodyStr is a string containing all statements in a UDF body.
   306  type RoutineBodyStr string
   307  
   308  // Format implements the NodeFormatter interface.
   309  func (node RoutineBodyStr) Format(ctx *FmtCtx) {
   310  	ctx.WriteString("AS ")
   311  	if ctx.flags.HasFlags(FmtTagDollarQuotes) {
   312  		ctx.WriteString("$funcbody$")
   313  	} else {
   314  		ctx.WriteString("$$")
   315  	}
   316  	if ctx.flags.HasFlags(FmtAnonymize) || ctx.flags.HasFlags(FmtHideConstants) {
   317  		ctx.WriteString("_")
   318  	} else {
   319  		ctx.WriteString(string(node))
   320  	}
   321  	if ctx.flags.HasFlags(FmtTagDollarQuotes) {
   322  		ctx.WriteString("$funcbody$")
   323  	} else {
   324  		ctx.WriteString("$$")
   325  	}
   326  }
   327  
   328  // RoutineParams represents a list of RoutineParam.
   329  type RoutineParams []RoutineParam
   330  
   331  // Format implements the NodeFormatter interface.
   332  func (node RoutineParams) Format(ctx *FmtCtx) {
   333  	for i := range node {
   334  		if i > 0 {
   335  			ctx.WriteString(", ")
   336  		}
   337  		ctx.FormatNode(&node[i])
   338  	}
   339  }
   340  
   341  // RoutineParam represents a parameter in a UDF signature.
   342  type RoutineParam struct {
   343  	Name       Name
   344  	Type       ResolvableTypeReference
   345  	Class      RoutineParamClass
   346  	DefaultVal Expr
   347  }
   348  
   349  // Format implements the NodeFormatter interface.
   350  func (node *RoutineParam) Format(ctx *FmtCtx) {
   351  	switch node.Class {
   352  	case RoutineParamIn:
   353  		ctx.WriteString("IN")
   354  	case RoutineParamOut:
   355  		ctx.WriteString("OUT")
   356  	case RoutineParamInOut:
   357  		ctx.WriteString("INOUT")
   358  	case RoutineParamVariadic:
   359  		ctx.WriteString("VARIADIC")
   360  	default:
   361  		panic(pgerror.New(pgcode.InvalidParameterValue, "unknown routine option"))
   362  	}
   363  	ctx.WriteString(" ")
   364  	if node.Name != "" {
   365  		ctx.FormatNode(&node.Name)
   366  		ctx.WriteString(" ")
   367  	}
   368  	ctx.FormatTypeReference(node.Type)
   369  	if node.DefaultVal != nil {
   370  		ctx.WriteString(" DEFAULT ")
   371  		ctx.FormatNode(node.DefaultVal)
   372  	}
   373  }
   374  
   375  // RoutineParamClass indicates what type of argument an arg is.
   376  type RoutineParamClass int
   377  
   378  const (
   379  	// RoutineParamIn args can only be used as input.
   380  	RoutineParamIn RoutineParamClass = iota
   381  	// RoutineParamOut args can only be used as output.
   382  	RoutineParamOut
   383  	// RoutineParamInOut args can be used as both input and output.
   384  	RoutineParamInOut
   385  	// RoutineParamVariadic args are variadic.
   386  	RoutineParamVariadic
   387  )
   388  
   389  // RoutineReturnType represent the return type of UDF.
   390  type RoutineReturnType struct {
   391  	Type  ResolvableTypeReference
   392  	SetOf bool
   393  }
   394  
   395  // DropRoutine represents a DROP FUNCTION or DROP PROCEDURE statement.
   396  type DropRoutine struct {
   397  	IfExists     bool
   398  	Procedure    bool
   399  	Routines     RoutineObjs
   400  	DropBehavior DropBehavior
   401  }
   402  
   403  // Format implements the NodeFormatter interface.
   404  func (node *DropRoutine) Format(ctx *FmtCtx) {
   405  	if node.Procedure {
   406  		ctx.WriteString("DROP PROCEDURE ")
   407  	} else {
   408  		ctx.WriteString("DROP FUNCTION ")
   409  	}
   410  	if node.IfExists {
   411  		ctx.WriteString("IF EXISTS ")
   412  	}
   413  	ctx.FormatNode(node.Routines)
   414  	if node.DropBehavior != DropDefault {
   415  		ctx.WriteString(" ")
   416  		ctx.WriteString(node.DropBehavior.String())
   417  	}
   418  }
   419  
   420  // RoutineObjs is a slice of RoutineObj.
   421  type RoutineObjs []RoutineObj
   422  
   423  // Format implements the NodeFormatter interface.
   424  func (node RoutineObjs) Format(ctx *FmtCtx) {
   425  	for i := range node {
   426  		if i > 0 {
   427  			ctx.WriteString(", ")
   428  		}
   429  		ctx.FormatNode(&node[i])
   430  	}
   431  }
   432  
   433  // RoutineObj represents a routine (function or procedure) object in DROP,
   434  // GRANT, and REVOKE statements.
   435  type RoutineObj struct {
   436  	FuncName RoutineName
   437  	Params   RoutineParams
   438  }
   439  
   440  // Format implements the NodeFormatter interface.
   441  func (node *RoutineObj) Format(ctx *FmtCtx) {
   442  	ctx.FormatNode(&node.FuncName)
   443  	if node.Params != nil {
   444  		ctx.WriteString("(")
   445  		ctx.FormatNode(node.Params)
   446  		ctx.WriteString(")")
   447  	}
   448  }
   449  
   450  // ParamTypes returns a slice of parameter types of the routine.
   451  func (node RoutineObj) ParamTypes(
   452  	ctx context.Context, res TypeReferenceResolver,
   453  ) ([]*types.T, error) {
   454  	// TODO(chengxiong): handle INOUT, OUT and VARIADIC argument classes when we
   455  	// support them. This is because only IN and INOUT arg types need to be
   456  	// considered to match a overload.
   457  	var argTypes []*types.T
   458  	if node.Params != nil {
   459  		argTypes = make([]*types.T, len(node.Params))
   460  		for i, arg := range node.Params {
   461  			typ, err := ResolveType(ctx, arg.Type, res)
   462  			if err != nil {
   463  				return nil, err
   464  			}
   465  			argTypes[i] = typ
   466  		}
   467  	}
   468  	return argTypes, nil
   469  }
   470  
   471  // AlterFunctionOptions represents a ALTER FUNCTION...action statement.
   472  type AlterFunctionOptions struct {
   473  	Function RoutineObj
   474  	Options  RoutineOptions
   475  }
   476  
   477  // Format implements the NodeFormatter interface.
   478  func (node *AlterFunctionOptions) Format(ctx *FmtCtx) {
   479  	ctx.WriteString("ALTER FUNCTION ")
   480  	ctx.FormatNode(&node.Function)
   481  	for _, option := range node.Options {
   482  		ctx.WriteString(" ")
   483  		ctx.FormatNode(option)
   484  	}
   485  }
   486  
   487  // AlterRoutineRename represents a ALTER FUNCTION...RENAME or
   488  // ALTER PROCEDURE...RENAME statement.
   489  type AlterRoutineRename struct {
   490  	Function  RoutineObj
   491  	NewName   Name
   492  	Procedure bool
   493  }
   494  
   495  // Format implements the NodeFormatter interface.
   496  func (node *AlterRoutineRename) Format(ctx *FmtCtx) {
   497  	if node.Procedure {
   498  		ctx.WriteString("ALTER PROCEDURE ")
   499  	} else {
   500  		ctx.WriteString("ALTER FUNCTION ")
   501  	}
   502  	ctx.FormatNode(&node.Function)
   503  	ctx.WriteString(" RENAME TO ")
   504  	ctx.FormatNode(&node.NewName)
   505  }
   506  
   507  // AlterRoutineSetSchema represents a ALTER FUNCTION...SET SCHEMA or
   508  // ALTER PROCEDURE...SET SCHEMA statement.
   509  type AlterRoutineSetSchema struct {
   510  	Function      RoutineObj
   511  	NewSchemaName Name
   512  	Procedure     bool
   513  }
   514  
   515  // Format implements the NodeFormatter interface.
   516  func (node *AlterRoutineSetSchema) Format(ctx *FmtCtx) {
   517  	if node.Procedure {
   518  		ctx.WriteString("ALTER PROCEDURE ")
   519  	} else {
   520  		ctx.WriteString("ALTER FUNCTION ")
   521  	}
   522  	ctx.FormatNode(&node.Function)
   523  	ctx.WriteString(" SET SCHEMA ")
   524  	ctx.FormatNode(&node.NewSchemaName)
   525  }
   526  
   527  // AlterRoutineSetOwner represents the ALTER FUNCTION...OWNER TO or
   528  // ALTER PROCEDURE...OWNER TO statement.
   529  type AlterRoutineSetOwner struct {
   530  	Function  RoutineObj
   531  	NewOwner  RoleSpec
   532  	Procedure bool
   533  }
   534  
   535  // Format implements the NodeFormatter interface.
   536  func (node *AlterRoutineSetOwner) Format(ctx *FmtCtx) {
   537  	if node.Procedure {
   538  		ctx.WriteString("ALTER PROCEDURE ")
   539  	} else {
   540  		ctx.WriteString("ALTER FUNCTION ")
   541  	}
   542  	ctx.FormatNode(&node.Function)
   543  	ctx.WriteString(" OWNER TO ")
   544  	ctx.FormatNode(&node.NewOwner)
   545  }
   546  
   547  // AlterFunctionDepExtension represents the ALTER FUNCTION...DEPENDS ON statement.
   548  type AlterFunctionDepExtension struct {
   549  	Function  RoutineObj
   550  	Remove    bool
   551  	Extension Name
   552  }
   553  
   554  // Format implements the NodeFormatter interface.
   555  func (node *AlterFunctionDepExtension) Format(ctx *FmtCtx) {
   556  	ctx.WriteString("ALTER FUNCTION  ")
   557  	ctx.FormatNode(&node.Function)
   558  	if node.Remove {
   559  		ctx.WriteString(" NO")
   560  	}
   561  	ctx.WriteString(" DEPENDS ON EXTENSION ")
   562  	ctx.WriteString(string(node.Extension))
   563  }
   564  
   565  // UDFDisallowanceVisitor is used to determine if a type checked expression
   566  // contains any UDF function sub-expression. It's needed only temporarily to
   567  // disallow any usage of UDF from relation objects.
   568  type UDFDisallowanceVisitor struct {
   569  	FoundUDF bool
   570  }
   571  
   572  // VisitPre implements the Visitor interface.
   573  func (v *UDFDisallowanceVisitor) VisitPre(expr Expr) (recurse bool, newExpr Expr) {
   574  	if funcExpr, ok := expr.(*FuncExpr); ok && funcExpr.ResolvedOverload().HasSQLBody() {
   575  		v.FoundUDF = true
   576  		return false, expr
   577  	}
   578  	return true, expr
   579  }
   580  
   581  // VisitPost implements the Visitor interface.
   582  func (v *UDFDisallowanceVisitor) VisitPost(expr Expr) (newNode Expr) {
   583  	return expr
   584  }
   585  
   586  // SchemaExprContext indicates in which schema change context an expression is being
   587  // used in. For example, DEFAULT VALUE of a column, CHECK CONSTRAINT's
   588  // expression, etc.
   589  type SchemaExprContext string
   590  
   591  const (
   592  	AlterColumnTypeUsingExpr        SchemaExprContext = "ALTER COLUMN TYPE USING EXPRESSION"
   593  	StoredComputedColumnExpr        SchemaExprContext = "STORED COMPUTED COLUMN"
   594  	VirtualComputedColumnExpr       SchemaExprContext = "VIRTUAL COMPUTED COLUMN"
   595  	ColumnOnUpdateExpr              SchemaExprContext = "ON UPDATE"
   596  	ColumnDefaultExprInAddColumn    SchemaExprContext = "DEFAULT (in ADD COLUMN)"
   597  	ColumnDefaultExprInNewTable     SchemaExprContext = "DEFAULT (in CREATE TABLE)"
   598  	ColumnDefaultExprInNewView      SchemaExprContext = "DEFAULT (in CREATE VIEW)"
   599  	ColumnDefaultExprInSetDefault   SchemaExprContext = "DEFAULT (in SET DEFAULT)"
   600  	CheckConstraintExpr             SchemaExprContext = "CHECK"
   601  	UniqueWithoutIndexPredicateExpr SchemaExprContext = "UNIQUE WITHOUT INDEX PREDICATE"
   602  	IndexPredicateExpr              SchemaExprContext = "INDEX PREDICATE"
   603  	ExpressionIndexElementExpr      SchemaExprContext = "EXPRESSION INDEX ELEMENT"
   604  	TTLExpirationExpr               SchemaExprContext = "TTL EXPIRATION EXPRESSION"
   605  	TTLDefaultExpr                  SchemaExprContext = "TTL DEFAULT"
   606  	TTLUpdateExpr                   SchemaExprContext = "TTL UPDATE"
   607  )
   608  
   609  func ComputedColumnExprContext(isVirtual bool) SchemaExprContext {
   610  	if isVirtual {
   611  		return VirtualComputedColumnExpr
   612  	}
   613  	return StoredComputedColumnExpr
   614  }
   615  
   616  // ValidateRoutineOptions checks whether there are conflicting or redundant
   617  // routine options in the given slice.
   618  func ValidateRoutineOptions(options RoutineOptions) error {
   619  	var hasLang, hasBody, hasLeakProof, hasVolatility, hasNullInputBehavior bool
   620  	conflictingErr := func(opt RoutineOption) error {
   621  		return errors.Wrapf(ErrConflictingRoutineOption, "%s", AsString(opt))
   622  	}
   623  	for _, option := range options {
   624  		switch option.(type) {
   625  		case RoutineLanguage:
   626  			if hasLang {
   627  				return conflictingErr(option)
   628  			}
   629  			hasLang = true
   630  		case RoutineBodyStr:
   631  			if hasBody {
   632  				return conflictingErr(option)
   633  			}
   634  			hasBody = true
   635  		case RoutineLeakproof:
   636  			if hasLeakProof {
   637  				return conflictingErr(option)
   638  			}
   639  			hasLeakProof = true
   640  		case RoutineVolatility:
   641  			if hasVolatility {
   642  				return conflictingErr(option)
   643  			}
   644  			hasVolatility = true
   645  		case RoutineNullInputBehavior:
   646  			if hasNullInputBehavior {
   647  				return conflictingErr(option)
   648  			}
   649  			hasNullInputBehavior = true
   650  		default:
   651  			return pgerror.Newf(pgcode.InvalidParameterValue, "unknown function option: ", AsString(option))
   652  		}
   653  	}
   654  
   655  	return nil
   656  }
   657  
   658  // GetRoutineVolatility tries to find a function volatility from the given list of
   659  // function options. If there is no volatility found, RoutineVolatile is
   660  // returned as the default.
   661  func GetRoutineVolatility(options RoutineOptions) RoutineVolatility {
   662  	for _, option := range options {
   663  		switch t := option.(type) {
   664  		case RoutineVolatility:
   665  			return t
   666  		}
   667  	}
   668  	return RoutineVolatile
   669  }