github.com/cockroachdb/cockroachdb-parser@v0.23.3-0.20240213214944-911057d40c9a/pkg/sql/sem/tree/function_name.go (about) 1 // Copyright 2016 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 "fmt" 16 "strings" 17 18 "github.com/cockroachdb/cockroachdb-parser/pkg/sql/pgwire/pgcode" 19 "github.com/cockroachdb/cockroachdb-parser/pkg/sql/pgwire/pgerror" 20 "github.com/cockroachdb/cockroachdb-parser/pkg/sql/sem/catconstants" 21 "github.com/cockroachdb/errors" 22 "github.com/lib/pq/oid" 23 ) 24 25 // ErrRoutineUndefined indicates that the required function is not found. It is 26 // used as the cause of the errors thrown when function resolution cannot find a 27 // required function. 28 var ErrRoutineUndefined = pgerror.Newf(pgcode.UndefinedFunction, "routine undefined") 29 30 // Function names are used in expressions in the FuncExpr node. 31 // General syntax: 32 // [ <context-prefix> . ] <function-name> 33 // 34 // The other syntax nodes hold a mutable ResolvableFunctionReference 35 // attribute. This is populated during parsing with an 36 // UnresolvedName, and gets assigned a FunctionDefinition upon the 37 // first call to its ResolveFunction() method. 38 39 // FunctionReferenceResolver is the interface that provides the ability to 40 // resolve built-in or user-defined function definitions from unresolved names. 41 type FunctionReferenceResolver interface { 42 // ResolveFunction resolves a group of overloads with the given function name 43 // within a search path. An error with ErrRoutineUndefined cause is returned 44 // if function does not exist. 45 // 46 // TODO(Chengxiong): Consider adding an optional slice of argument types to 47 // the input of this method, so that we can try to narrow down the scope of 48 // overloads a bit earlier and decrease the possibility of ambiguous error 49 // on function properties. 50 ResolveFunction( 51 ctx context.Context, name UnresolvedRoutineName, path SearchPath, 52 ) (*ResolvedFunctionDefinition, error) 53 54 // ResolveFunctionByOID looks up a function overload by using a given oid. 55 // Function name is returned together with the overload. Error is thrown if 56 // there is no function with the same oid. 57 ResolveFunctionByOID( 58 ctx context.Context, oid oid.Oid, 59 ) (*RoutineName, *Overload, error) 60 } 61 62 // ResolvableFunctionReference implements the editable reference call of a 63 // FuncExpr. 64 type ResolvableFunctionReference struct { 65 // ReferenceByName keeps track of the name that was used to resolve the 66 // function, if one was used. This is used for metadata dependency tracking. 67 ReferenceByName *UnresolvedObjectName 68 FunctionReference 69 } 70 71 // Resolve converts a ResolvableFunctionReference into a *FunctionDefinition. If 72 // the reference has already been resolved, it simply returns the definition. If 73 // a FunctionReferenceResolver is provided, it will be used to resolve the 74 // function definition. Otherwise, the default resolution of 75 // UnresolvedName.ResolveFunction is used. 76 func (ref *ResolvableFunctionReference) Resolve( 77 ctx context.Context, path SearchPath, resolver FunctionReferenceResolver, 78 ) (*ResolvedFunctionDefinition, error) { 79 switch t := ref.FunctionReference.(type) { 80 case *ResolvedFunctionDefinition: 81 return t, nil 82 case *FunctionDefinition: 83 // TODO(Chengxiong): get rid of FunctionDefinition entirely. 84 parts := strings.Split(t.Name, ".") 85 if len(parts) > 2 { 86 // In theory, this should not happen since all builtin functions are 87 // defined within virtual schema and don't belong to any database catalog. 88 return nil, errors.AssertionFailedf("invalid builtin function name: %q", t.Name) 89 } 90 fullName := t.Name 91 if len(parts) == 1 { 92 fullName = catconstants.PgCatalogName + "." + t.Name 93 } 94 fd := ResolvedBuiltinFuncDefs[fullName] 95 ref.FunctionReference = fd 96 return fd, nil 97 case *UnresolvedName: 98 if resolver == nil { 99 // If a resolver is not provided, just try to fetch a builtin function. 100 fn, err := t.ToRoutineName() 101 if err != nil { 102 return nil, err 103 } 104 fd, err := GetBuiltinFuncDefinitionOrFail(fn, path) 105 if err != nil { 106 return nil, err 107 } 108 ref.FunctionReference = fd 109 return fd, nil 110 } 111 // Use the resolver if it is provided. 112 fd, err := resolver.ResolveFunction(ctx, MakeUnresolvedFunctionName(t), path) 113 if err != nil { 114 return nil, err 115 } 116 referenceByName, _ := t.ToUnresolvedObjectName(NoAnnotation) 117 ref.ReferenceByName = &referenceByName 118 ref.FunctionReference = fd 119 return fd, nil 120 case *FunctionOID: 121 if resolver == nil { 122 return GetBuiltinFunctionByOIDOrFail(t.OID) 123 } 124 fnName, o, err := resolver.ResolveFunctionByOID(ctx, t.OID) 125 if err != nil { 126 return nil, err 127 } 128 fd := &ResolvedFunctionDefinition{ 129 Name: fnName.Object(), 130 Overloads: []QualifiedOverload{{Schema: fnName.Schema(), Overload: o}}, 131 } 132 ref.FunctionReference = fd 133 return fd, nil 134 default: 135 return nil, errors.AssertionFailedf("unknown resolvable function reference type %s", t) 136 } 137 } 138 139 // WrapFunction creates a new ResolvableFunctionReference holding a pre-resolved 140 // function from a built-in function name. Helper for grammar rules and 141 // execbuilder. 142 // 143 // TODO(Chengxiong): get rid of FunctionDefinition entirely and use 144 // ResolvedFunctionDefinition instead. 145 func WrapFunction(n string) ResolvableFunctionReference { 146 fd, ok := FunDefs[n] 147 if !ok { 148 return ResolvableFunctionReference{ 149 FunctionReference: &FunctionDefinition{ 150 Name: n, 151 }, 152 } 153 } 154 return ResolvableFunctionReference{FunctionReference: fd} 155 } 156 157 // FunctionReference is the common interface to UnresolvedName and QualifiedFunctionName. 158 type FunctionReference interface { 159 fmt.Stringer 160 NodeFormatter 161 functionReference() 162 } 163 164 var _ FunctionReference = &UnresolvedName{} 165 var _ FunctionReference = &FunctionDefinition{} 166 var _ FunctionReference = &ResolvedFunctionDefinition{} 167 168 func (*UnresolvedName) functionReference() {} 169 func (*FunctionDefinition) functionReference() {} 170 func (*ResolvedFunctionDefinition) functionReference() {} 171 func (*FunctionOID) functionReference() {} 172 173 type FunctionOID struct { 174 OID oid.Oid 175 } 176 177 func (o *FunctionOID) String() string { 178 return AsString(o) 179 } 180 181 func (o *FunctionOID) Format(ctx *FmtCtx) { 182 ctx.WriteString(fmt.Sprintf("[FUNCTION %d]", o.OID)) 183 }