forked from cockroachdb/cockroach
/
placeholders.go
155 lines (138 loc) · 4.45 KB
/
placeholders.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
// Copyright 2016 The Cockroach Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied. See the License for the specific language governing
// permissions and limitations under the License.
//
// Author: Raphael 'kena' Poss (knz@cockroachlabs.com)
package parser
import (
"fmt"
"sort"
"strings"
"github.com/cockroachdb/cockroach/pkg/util"
)
// PlaceholderTypes relates placeholder names to their resolved type.
type PlaceholderTypes map[string]Type
// QueryArguments relates placeholder names to their provided query argument.
type QueryArguments map[string]Datum
// PlaceholderInfo defines the interface to SQL placeholders.
type PlaceholderInfo struct {
Values QueryArguments
Types PlaceholderTypes
}
// MakePlaceholderInfo constructs an empty PlaceholderInfo.
func MakePlaceholderInfo() PlaceholderInfo {
res := PlaceholderInfo{}
res.Clear()
return res
}
// Clear resets the placeholder info map.
func (p *PlaceholderInfo) Clear() {
p.Types = PlaceholderTypes{}
p.Values = QueryArguments{}
}
// Assign resets the PlaceholderInfo to the contents of src.
// If src is nil, the map is cleared.
func (p *PlaceholderInfo) Assign(src *PlaceholderInfo) {
if src != nil {
*p = *src
} else {
p.Clear()
}
}
// FillUnassigned sets all unsassigned placeholders to NULL.
func (p *PlaceholderInfo) FillUnassigned() {
for pn := range p.Types {
if _, ok := p.Values[pn]; !ok {
p.Values[pn] = DNull
}
}
}
// AssertAllAssigned ensures that all placeholders that are used also
// have a value assigned.
func (p *PlaceholderInfo) AssertAllAssigned() error {
var missing []string
for pn := range p.Types {
if _, ok := p.Values[pn]; !ok {
missing = append(missing, "$"+pn)
}
}
if len(missing) > 0 {
sort.Strings(missing)
return fmt.Errorf("no value provided for placeholder%s: %s",
util.Pluralize(int64(len(missing))),
strings.Join(missing, ", "),
)
}
return nil
}
// Type returns the known type of a placeholder.
// Returns false in the 2nd value if the placeholder is not typed.
func (p *PlaceholderInfo) Type(name string) (Type, bool) {
if t, ok := p.Types[name]; ok {
return t, true
}
return nil, false
}
// Value returns the known value of a placeholder. Returns false in
// the 2nd value if the placeholder does not have a value.
func (p *PlaceholderInfo) Value(name string) (Datum, bool) {
if v, ok := p.Values[name]; ok {
return v, true
}
return nil, false
}
// SetValue assigns a known value to a placeholder.
// If no type is known yet, it is inferred from the assigned value.
func (p *PlaceholderInfo) SetValue(name string, val Datum) {
if _, ok := p.Values[name]; ok {
panic(fmt.Sprintf("placeholder $%s already has a value", name))
}
p.Values[name] = val
if _, ok := p.Types[name]; !ok {
// No type yet, infer from value
p.Types[name] = val.ResolvedType()
}
}
// SetType assignes a known type to a placeholder.
// Reports an error if another type was previously assigned.
func (p *PlaceholderInfo) SetType(name string, typ Type) error {
if t, ok := p.Types[name]; ok && !typ.Equivalent(t) {
return fmt.Errorf("placeholder %s already has type %s, cannot assign %s", name, t, typ)
}
p.Types[name] = typ
return nil
}
// SetTypes resets the type and values in the map and replaces the
// types map by an alias to src. If src is nil, the map is cleared.
// The types map is aliased because the invoking code from
// pgwire/v3.go for sql.Prepare needs to receive the updated type
// assignments after Prepare completes.
func (p *PlaceholderInfo) SetTypes(src PlaceholderTypes) {
if src != nil {
p.Types = src
p.Values = QueryArguments{}
} else {
p.Clear()
}
}
// IsUnresolvedPlaceholder returns whether expr is an unresolved placeholder. In
// other words, it returns whether the provided expression is a placeholder
// expression or a placeholder expression within nested parentheses, and if so,
// whether the placeholder's type remains unset in the PlaceholderInfo.
func (p *PlaceholderInfo) IsUnresolvedPlaceholder(expr Expr) bool {
if t, ok := StripParens(expr).(*Placeholder); ok {
_, res := p.Types[t.Name]
return !res
}
return false
}