github.com/cockroachdb/cockroachdb-parser@v0.23.3-0.20240213214944-911057d40c9a/pkg/sql/sem/tree/placeholders.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 "bytes" 15 "fmt" 16 "math" 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/types" 21 ) 22 23 // PlaceholderIdx is the 0-based index of a placeholder. Placeholder "$1" 24 // has PlaceholderIdx=0. 25 type PlaceholderIdx uint16 26 27 // MaxPlaceholderIdx is the maximum allowed value of a PlaceholderIdx. 28 // The pgwire protocol is limited to 2^16 placeholders, so we limit the IDs to 29 // this range as well. 30 const MaxPlaceholderIdx = math.MaxUint16 31 32 // String returns the index as a placeholder string representation ($1, $2 etc). 33 func (idx PlaceholderIdx) String() string { 34 return fmt.Sprintf("$%d", idx+1) 35 } 36 37 // PlaceholderTypes stores placeholder types (or type hints), one per 38 // PlaceholderIdx. The slice is always pre-allocated to the number of 39 // placeholders in the statement. Entries that don't yet have a type are nil. 40 type PlaceholderTypes []*types.T 41 42 // Identical returns true if two PlaceholderTypes contain the same types. 43 func (pt PlaceholderTypes) Identical(other PlaceholderTypes) bool { 44 if len(pt) != len(other) { 45 return false 46 } 47 for i, t := range pt { 48 switch { 49 case t == nil && other[i] == nil: 50 case t == nil || other[i] == nil: 51 return false 52 case !t.Identical(other[i]): 53 return false 54 } 55 } 56 return true 57 } 58 59 // AssertAllSet verifies that all types have been set and returns an error 60 // otherwise. 61 func (pt PlaceholderTypes) AssertAllSet() error { 62 for i := range pt { 63 if pt[i] == nil { 64 return placeholderTypeAmbiguityError(PlaceholderIdx(i)) 65 } 66 } 67 return nil 68 } 69 70 // QueryArguments stores query arguments, one per PlaceholderIdx. 71 // 72 // A nil value represents a NULL argument. 73 type QueryArguments []TypedExpr 74 75 func (qa QueryArguments) String() string { 76 if len(qa) == 0 { 77 return "{}" 78 } 79 var buf bytes.Buffer 80 buf.WriteByte('{') 81 sep := "" 82 for k, v := range qa { 83 fmt.Fprintf(&buf, "%s%s:%q", sep, PlaceholderIdx(k), v) 84 sep = ", " 85 } 86 buf.WriteByte('}') 87 return buf.String() 88 } 89 90 // PlaceholderTypesInfo encapsulates typing information for placeholders. 91 type PlaceholderTypesInfo struct { 92 // TypeHints contains the initially set type hints for each placeholder if 93 // present. It is not changed during query type checking. 94 TypeHints PlaceholderTypes 95 // Types contains the final types set for each placeholder after type 96 // checking. 97 Types PlaceholderTypes 98 } 99 100 // Type returns the known type of a placeholder. If there is no known type yet 101 // but there is a type hint, returns the type hint. 102 func (p *PlaceholderTypesInfo) Type(idx PlaceholderIdx) (_ *types.T, ok bool, _ error) { 103 if len(p.Types) <= int(idx) { 104 return nil, false, NewNoValueProvidedForPlaceholderErr(idx) 105 } 106 t := p.Types[idx] 107 if t == nil && len(p.TypeHints) > int(idx) { 108 t = p.TypeHints[idx] 109 } 110 return t, t != nil, nil 111 } 112 113 // ValueType returns the type of the value that must be supplied for a placeholder. 114 // This is the type hint given by the client if there is one, or the placeholder 115 // type if there isn't one. This can differ from Type(idx) when a client hint is 116 // overridden (see Placeholder.Eval). 117 func (p *PlaceholderTypesInfo) ValueType(idx PlaceholderIdx) (_ *types.T, ok bool) { 118 var t *types.T 119 if len(p.TypeHints) >= int(idx) { 120 t = p.TypeHints[idx] 121 } 122 if t == nil { 123 t = p.Types[idx] 124 } 125 return t, (t != nil) 126 } 127 128 // SetType assigns a known type to a placeholder. 129 // Reports an error if another type was previously assigned. 130 func (p *PlaceholderTypesInfo) SetType(idx PlaceholderIdx, typ *types.T) error { 131 if t := p.Types[idx]; t != nil { 132 if !typ.Equivalent(t) { 133 return pgerror.Newf( 134 pgcode.DatatypeMismatch, 135 "placeholder %s already has type %s, cannot assign %s", idx, t, typ) 136 } 137 // If `t` is not ambiguous or if `typ` is ambiguous, then we shouldn't 138 // change the type that's already set. Otherwise, we can use `typ` since 139 // it is more specific. 140 if !t.IsAmbiguous() || typ.IsAmbiguous() { 141 return nil 142 } 143 } 144 p.Types[idx] = typ 145 return nil 146 } 147 148 // PlaceholderInfo defines the interface to SQL placeholders. 149 type PlaceholderInfo struct { 150 PlaceholderTypesInfo 151 152 Values QueryArguments 153 } 154 155 // Init initializes a PlaceholderInfo structure appropriate for the given number 156 // of placeholders, and with the given (optional) type hints. 157 func (p *PlaceholderInfo) Init(numPlaceholders int, typeHints PlaceholderTypes) error { 158 if typeHints == nil { 159 p.TypeHints = make(PlaceholderTypes, numPlaceholders) 160 p.Types = make(PlaceholderTypes, numPlaceholders) 161 } else { 162 p.Types = make(PlaceholderTypes, len(typeHints)) 163 p.TypeHints = typeHints 164 } 165 p.Values = nil 166 return nil 167 } 168 169 // Assign resets the PlaceholderInfo to the contents of src. 170 // If src is nil, a new structure is initialized. 171 func (p *PlaceholderInfo) Assign(src *PlaceholderInfo, numPlaceholders int) error { 172 if src != nil { 173 *p = *src 174 return nil 175 } 176 return p.Init(numPlaceholders, nil /* typeHints */) 177 } 178 179 // MaybeExtendTypes is to fill the nil types with the type hints, if exists. 180 func (p *PlaceholderInfo) MaybeExtendTypes() { 181 if len(p.TypeHints) >= len(p.Types) { 182 for i, t := range p.Types { 183 if t == nil { 184 p.Types[i] = p.TypeHints[i] 185 } 186 } 187 } 188 } 189 190 // Value returns the known value of a placeholder. Returns false in 191 // the 2nd value if the placeholder does not have a value. 192 func (p *PlaceholderInfo) Value(idx PlaceholderIdx) (TypedExpr, bool) { 193 if len(p.Values) <= int(idx) || p.Values[idx] == nil { 194 return nil, false 195 } 196 return p.Values[idx], true 197 } 198 199 // IsUnresolvedPlaceholder returns whether expr is an unresolved placeholder. In 200 // other words, it returns whether the provided expression is a placeholder 201 // expression or a placeholder expression within nested parentheses, and if so, 202 // whether the placeholder's type remains unset in the PlaceholderInfo. 203 func (p *PlaceholderInfo) IsUnresolvedPlaceholder(expr Expr) bool { 204 if t, ok := StripParens(expr).(*Placeholder); ok { 205 _, res, err := p.Type(t.Idx) 206 return !(err == nil && res) 207 } 208 return false 209 } 210 211 // NewNoValueProvidedForPlaceholderErr constructs an error indicating a missing 212 // placeholder value. 213 func NewNoValueProvidedForPlaceholderErr(pIdx PlaceholderIdx) error { 214 return pgerror.Newf(pgcode.UndefinedParameter, 215 "no value provided for placeholder: $%d", pIdx+1, 216 ) 217 }