forked from cockroachdb/cockroach
/
format.go
240 lines (214 loc) · 8.33 KB
/
format.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
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
// 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.
package parser
import (
"bytes"
"fmt"
)
type fmtFlags struct {
showTypes bool
ShowTableAliases bool
symbolicVars bool
hideConstants bool
// tableNameFormatter will be called on all NormalizableTableNames if it is
// non-nil.
tableNameFormatter func(*NormalizableTableName, *bytes.Buffer, FmtFlags)
// indexedVarFormat is an optional interceptor for
// IndexedVarContainer.IndexedVarFormat calls; it can be used to
// customize the formatting of IndexedVars.
indexedVarFormat func(buf *bytes.Buffer, f FmtFlags, c IndexedVarContainer, idx int)
// starDatumFormat is an optional interceptor for StarDatum.Format calls,
// can be used to customize the formatting of StarDatums.
starDatumFormat func(buf *bytes.Buffer, f FmtFlags)
// If true, non-function names are replaced by underscores.
anonymize bool
// If true, strings will be rendered without wrapping quotes if they
// contain no special characters.
bareStrings bool
// If true, identifiers will be rendered without wrapping quotes.
bareIdentifiers bool
// If true, strings will be formatted for being contents of ARRAYs.
withinArray bool
// If true, datums and placeholders will have type annotations (like
// :::interval) as necessary to disambiguate between possible type
// resolutions.
disambiguateDatumTypes bool
// If false, passwords are replaced by *****.
showPasswords bool
// If true, always prints qualified names even if originally omitted.
alwaysQualify bool
// If true, grouping parentheses are always shown. Used for testing.
alwaysParens bool
}
// FmtFlags enables conditional formatting in the pretty-printer.
type FmtFlags *fmtFlags
// FmtSimple instructs the pretty-printer to produce
// a straightforward representation.
var FmtSimple FmtFlags = &fmtFlags{}
// FmtSimpleWithPasswords instructs the pretty-printer to produce a
// straightforward representation that does not suppress passwords.
var FmtSimpleWithPasswords FmtFlags = &fmtFlags{showPasswords: true}
// FmtShowTypes instructs the pretty-printer to
// annotate expressions with their resolved types.
var FmtShowTypes FmtFlags = &fmtFlags{showTypes: true}
// FmtBareStrings instructs the pretty-printer to print strings without
// wrapping quotes, if the string contains no special characters.
var FmtBareStrings FmtFlags = &fmtFlags{bareStrings: true}
// FmtArrays instructs the pretty-printer to print strings without
// wrapping quotes, if the string contains no special characters.
var FmtArrays FmtFlags = &fmtFlags{withinArray: true, bareStrings: true}
// FmtBareIdentifiers instructs the pretty-printer to print
// identifiers without wrapping quotes in any case.
var FmtBareIdentifiers FmtFlags = &fmtFlags{bareIdentifiers: true}
// FmtParsable instructs the pretty-printer to produce a representation that
// can be parsed into an equivalent expression (useful for serialization of
// expressions).
var FmtParsable FmtFlags = &fmtFlags{disambiguateDatumTypes: true}
// FmtCheckEquivalence instructs the pretty-printer to produce a representation
// that can be used to check equivalence of expressions. Specifically:
// - IndexedVars are formatted using symbolic notation (to disambiguate
// columns).
// - datum types are disambiguated with explicit type
// annotations. This is necessary because datums of different types
// can otherwise be formatted to the same string: (for example the
// DDecimal 1 and the DInt 1).
var FmtCheckEquivalence FmtFlags = &fmtFlags{symbolicVars: true, disambiguateDatumTypes: true}
// FmtHideConstants instructs the pretty-printer to produce a
// representation that does not disclose query-specific data.
var FmtHideConstants FmtFlags = &fmtFlags{hideConstants: true}
// FmtAnonymize instructs the pretty-printer to remove
// any name but function names.
// TODO(knz): temporary until a better solution is found for #13968
var FmtAnonymize FmtFlags = &fmtFlags{anonymize: true}
// FmtSimpleQualified instructs the pretty-printer to produce
// a straightforward representation that qualifies table names.
var FmtSimpleQualified FmtFlags = &fmtFlags{alwaysQualify: true}
// FmtReformatTableNames returns FmtFlags that instructs the pretty-printer
// to substitute the printing of table names using the provided function.
func FmtReformatTableNames(
base FmtFlags, fn func(*NormalizableTableName, *bytes.Buffer, FmtFlags),
) FmtFlags {
f := *base
f.tableNameFormatter = fn
return &f
}
// StripTypeFormatting removes the flag that extracts types from the format flags,
// so as to enable rendering expressions for which types have not been computed yet.
func StripTypeFormatting(f FmtFlags) FmtFlags {
nf := *f
nf.showTypes = false
return &nf
}
// FmtExpr returns FmtFlags that indicate how the pretty-printer
// should format expressions.
func FmtExpr(base FmtFlags, showTypes bool, symbolicVars bool, showTableAliases bool) FmtFlags {
f := *base
f.showTypes = showTypes
f.symbolicVars = symbolicVars
f.ShowTableAliases = showTableAliases
return &f
}
// FmtIndexedVarFormat returns FmtFlags that customizes the printing of
// IndexedVars using the provided function.
func FmtIndexedVarFormat(
base FmtFlags, fn func(buf *bytes.Buffer, f FmtFlags, c IndexedVarContainer, idx int),
) FmtFlags {
f := *base
f.indexedVarFormat = fn
return &f
}
// FmtStarDatumFormat returns FmtFlags that customizes the printing of
// StarDatums using the provided function.
func FmtStarDatumFormat(base FmtFlags, fn func(buf *bytes.Buffer, f FmtFlags)) FmtFlags {
f := *base
f.starDatumFormat = fn
return &f
}
// NodeFormatter is implemented by nodes that can be pretty-printed.
type NodeFormatter interface {
// Format performs pretty-printing towards a bytes buffer. The flags argument
// influences the results. Most callers should use FormatNode instead.
Format(buf *bytes.Buffer, flags FmtFlags)
}
// FormatNode recurses into a node for pretty-printing.
// Flag-driven special cases can hook into this.
func FormatNode(buf *bytes.Buffer, f FmtFlags, n NodeFormatter) {
if f.showTypes {
if te, ok := n.(TypedExpr); ok {
buf.WriteByte('(')
formatNodeOrHideConstants(buf, f, n)
buf.WriteString(")[")
if rt := te.ResolvedType(); rt == nil {
// An attempt is made to pretty-print an expression that was
// not assigned a type yet. This should not happen, so we make
// it clear in the output this needs to be investigated
// further.
buf.WriteString(fmt.Sprintf("??? %v", te))
} else {
buf.WriteString(rt.String())
}
buf.WriteByte(']')
return
}
}
if f.alwaysParens {
if _, ok := n.(Expr); ok {
buf.WriteByte('(')
}
}
formatNodeOrHideConstants(buf, f, n)
if f.alwaysParens {
if _, ok := n.(Expr); ok {
buf.WriteByte(')')
}
}
if f.disambiguateDatumTypes {
var typ Type
if d, isDatum := n.(Datum); isDatum {
if d.AmbiguousFormat() {
typ = d.ResolvedType()
}
} else if p, isPlaceholder := n.(*Placeholder); isPlaceholder {
typ = p.typ
}
if typ != nil {
buf.WriteString(":::")
colType, err := DatumTypeToColumnType(typ)
if err != nil {
panic(err)
}
FormatNode(buf, f, colType)
}
}
}
// AsStringWithFlags pretty prints a node to a string given specific flags.
func AsStringWithFlags(n NodeFormatter, f FmtFlags) string {
var buf bytes.Buffer
FormatNode(&buf, f, n)
return buf.String()
}
// AsString pretty prints a node to a string.
func AsString(n NodeFormatter) string {
return AsStringWithFlags(n, FmtSimple)
}
// ErrString pretty prints a node to a string. Identifiers are not quoted.
func ErrString(n NodeFormatter) string {
return AsStringWithFlags(n, FmtBareIdentifiers)
}
// Serialize pretty prints a node to a string using FmtParsable; it is
// appropriate when we store expressions into strings that are later parsed back
// into expressions.
func Serialize(n NodeFormatter) string {
return AsStringWithFlags(n, FmtParsable)
}