-
Notifications
You must be signed in to change notification settings - Fork 3.9k
/
Copy pathcolumn.go
486 lines (435 loc) · 16 KB
/
column.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
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
// Copyright 2021 The Cockroach Authors.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt.
//
// As of the Change Date specified in that file, in accordance with
// the Business Source License, use of this software will be governed
// by the Apache License, Version 2.0, included in the file
// licenses/APL.txt.
package tabledesc
import (
"strings"
"github.com/cockroachdb/cockroach/pkg/sql/catalog"
"github.com/cockroachdb/cockroach/pkg/sql/catalog/catenumpb"
"github.com/cockroachdb/cockroach/pkg/sql/catalog/catpb"
"github.com/cockroachdb/cockroach/pkg/sql/catalog/colinfo"
"github.com/cockroachdb/cockroach/pkg/sql/catalog/descpb"
"github.com/cockroachdb/cockroach/pkg/sql/catalog/fetchpb"
"github.com/cockroachdb/cockroach/pkg/sql/catalog/schemaexpr"
"github.com/cockroachdb/cockroach/pkg/sql/parser"
"github.com/cockroachdb/cockroach/pkg/sql/sem/tree"
"github.com/cockroachdb/cockroach/pkg/sql/types"
"github.com/cockroachdb/cockroach/pkg/util/protoutil"
)
var _ catalog.Column = (*column)(nil)
// column implements the catalog.Column interface by wrapping the protobuf
// column descriptor along with some metadata from its parent table
// descriptor.
type column struct {
maybeMutation
desc *descpb.ColumnDescriptor
isBecomingNotNull bool
ordinal int
}
// ColumnDesc returns the underlying protobuf descriptor.
// Ideally, this method should be called as rarely as possible.
func (w column) ColumnDesc() *descpb.ColumnDescriptor {
return w.desc
}
// ColumnDescDeepCopy returns a deep copy of the underlying protobuf descriptor.
func (w column) ColumnDescDeepCopy() descpb.ColumnDescriptor {
return *protoutil.Clone(w.desc).(*descpb.ColumnDescriptor)
}
// DeepCopy returns a deep copy of the receiver.
func (w column) DeepCopy() catalog.Column {
desc := w.ColumnDescDeepCopy()
return &column{
maybeMutation: w.maybeMutation,
desc: &desc,
ordinal: w.ordinal,
}
}
// Ordinal returns the ordinal of the column in its parent TableDescriptor.
// The ordinal is defined as follows:
// - [:len(desc.Columns)] is the range of public columns,
// - [len(desc.Columns):] is the range of non-public columns.
func (w column) Ordinal() int {
return w.ordinal
}
// Public returns true iff the column is active, i.e. readable.
func (w column) Public() bool {
return !w.IsMutation() && !w.IsSystemColumn()
}
// GetID returns the column ID.
func (w column) GetID() descpb.ColumnID {
return w.desc.ID
}
// GetName returns the column name as a string.
func (w column) GetName() string {
return w.desc.Name
}
// ColName returns the column name as a tree.Name.
func (w column) ColName() tree.Name {
return w.desc.ColName()
}
// HasType returns true iff the column type is set.
func (w column) HasType() bool {
return w.desc.Type != nil
}
// GetType returns the column type.
func (w column) GetType() *types.T {
return w.desc.Type
}
// IsNullable returns true iff the column allows NULL values.
func (w column) IsNullable() bool {
return w.desc.Nullable
}
// HasDefault returns true iff the column has a default expression set.
func (w column) HasDefault() bool {
return w.desc.HasDefault()
}
// HasNullDefault checks that the column descriptor has a default of NULL.
func (w column) HasNullDefault() bool {
if !w.HasDefault() {
return false
}
// We ignore the error because what are we going to do with it? It means
// that the default expressions is not parsable. Somebody with a context
// who needs to use it will be in a better place to log it. If it is not
// parsable, it is not NULL.
defaultExpr, _ := parser.ParseExpr(w.GetDefaultExpr())
return defaultExpr == tree.DNull
}
// GetDefaultExpr returns the column default expression if it exists,
// empty string otherwise.
func (w column) GetDefaultExpr() string {
if !w.HasDefault() {
return ""
}
return *w.desc.DefaultExpr
}
// HasOnUpdate returns true iff the column has an on update expression set.
func (w column) HasOnUpdate() bool {
return w.desc.HasOnUpdate()
}
// GetOnUpdateExpr returns the column on update expression if it exists,
// empty string otherwise.
func (w column) GetOnUpdateExpr() string {
if !w.HasOnUpdate() {
return ""
}
return *w.desc.OnUpdateExpr
}
// IsComputed returns true iff the column is a computed column.
func (w column) IsComputed() bool {
return w.desc.IsComputed()
}
// GetComputeExpr returns the column computed expression if it exists,
// empty string otherwise.
func (w column) GetComputeExpr() string {
if !w.IsComputed() {
return ""
}
return *w.desc.ComputeExpr
}
// IsHidden returns true iff the column is not visible.
func (w column) IsHidden() bool {
return w.desc.Hidden
}
// IsInaccessible returns true iff the column is inaccessible.
func (w column) IsInaccessible() bool {
return w.desc.Inaccessible
}
// IsExpressionIndexColumn returns true iff the column is an an inaccessible
// virtual computed column that represents an expression in an expression index.
func (w column) IsExpressionIndexColumn() bool {
return w.IsInaccessible() && w.IsVirtual()
}
// NumUsesSequences returns the number of sequences used by this column.
func (w column) NumUsesSequences() int {
return len(w.desc.UsesSequenceIds)
}
// GetUsesSequenceID returns the ID of a sequence used by this column.
func (w column) GetUsesSequenceID(usesSequenceOrdinal int) descpb.ID {
return w.desc.UsesSequenceIds[usesSequenceOrdinal]
}
// NumOwnsSequences returns the number of sequences owned by this column.
func (w column) NumOwnsSequences() int {
return len(w.desc.OwnsSequenceIds)
}
// GetOwnsSequenceID returns the ID of a sequence owned by this column.
func (w column) GetOwnsSequenceID(ownsSequenceOrdinal int) descpb.ID {
return w.desc.OwnsSequenceIds[ownsSequenceOrdinal]
}
// IsVirtual returns true iff the column is a virtual column.
func (w column) IsVirtual() bool {
return w.desc.Virtual
}
// CheckCanBeInboundFKRef returns whether the given column can be on the
// referenced (target) side of a foreign key relation.
func (w column) CheckCanBeInboundFKRef() error {
return w.desc.CheckCanBeInboundFKRef()
}
// CheckCanBeOutboundFKRef returns whether the given column can be on the
// referencing (origin) side of a foreign key relation.
func (w column) CheckCanBeOutboundFKRef() error {
return w.desc.CheckCanBeOutboundFKRef()
}
// GetPGAttributeNum returns the PGAttributeNum of the column descriptor
// if the PGAttributeNum is set (non-zero). Returns the ID of the
// column descriptor if the PGAttributeNum is not set.
func (w column) GetPGAttributeNum() descpb.PGAttributeNum {
return w.desc.GetPGAttributeNum()
}
// IsSystemColumn returns true iff the column is a system column.
func (w column) IsSystemColumn() bool {
return w.desc.SystemColumnKind != catpb.SystemColumnKind_NONE
}
// IsGeneratedAsIdentity returns true iff the column is created
// with GENERATED {ALWAYS | BY DEFAULT} AS IDENTITY syntax.
func (w column) IsGeneratedAsIdentity() bool {
return w.desc.GeneratedAsIdentityType != catpb.GeneratedAsIdentityType_NOT_IDENTITY_COLUMN
}
// IsGeneratedAlwaysAsIdentity returns true iff the column is created
// with GENERATED ALWAYS AS IDENTITY syntax.
func (w column) IsGeneratedAlwaysAsIdentity() bool {
return w.desc.GeneratedAsIdentityType == catpb.GeneratedAsIdentityType_GENERATED_ALWAYS
}
// IsGeneratedByDefaultAsIdentity returns true iff the column is created
// with GENERATED BY DEFAULT AS IDENTITY syntax.
func (w column) IsGeneratedByDefaultAsIdentity() bool {
return w.desc.GeneratedAsIdentityType == catpb.GeneratedAsIdentityType_GENERATED_BY_DEFAULT
}
// GetGeneratedAsIdentityType returns the type of how the column was
// created as an IDENTITY column.
// If the column is created with `GENERATED ALWAYS AS IDENTITY` syntax,
// it will return descpb.GeneratedAsIdentityType_GENERATED_ALWAYS;
// if the column is created with `GENERATED BY DEFAULT AS IDENTITY` syntax,
// it will return descpb.GeneratedAsIdentityType_GENERATED_BY_DEFAULT;
// otherwise, returns descpb.GeneratedAsIdentityType_NOT_IDENTITY_COLUMN.
func (w column) GetGeneratedAsIdentityType() catpb.GeneratedAsIdentityType {
return w.desc.GeneratedAsIdentityType
}
// GetGeneratedAsIdentitySequenceOptionStr returns the string representation
// of the column's `GENERATED AS IDENTITY` sequence option if it exists, empty
// string otherwise.
func (w column) GetGeneratedAsIdentitySequenceOptionStr() string {
if !w.HasGeneratedAsIdentitySequenceOption() {
return ""
}
return strings.TrimSpace(*w.desc.GeneratedAsIdentitySequenceOption)
}
// GetGeneratedAsIdentitySequenceOption returns the column's `GENERATED AS
// IDENTITY` sequence option if it exists, and possible error.
// If the column is not an identity column, return nil for both sequence option
// and the error.
// Note it doesn't return the sequence owner info.
func (w column) GetGeneratedAsIdentitySequenceOption(
defaultIntSize int32,
) (*descpb.TableDescriptor_SequenceOpts, error) {
if !w.HasGeneratedAsIdentitySequenceOption() {
return nil, nil
}
seqOpts, err := schemaexpr.ParseSequenceOpts(*w.desc.GeneratedAsIdentitySequenceOption, defaultIntSize)
if err != nil {
return nil, err
}
return seqOpts, nil
}
// HasGeneratedAsIdentitySequenceOption returns true if there is a
// customized sequence option when this column is created as a
// `GENERATED AS IDENTITY` column.
func (w column) HasGeneratedAsIdentitySequenceOption() bool {
return w.desc.GeneratedAsIdentitySequenceOption != nil
}
// columnCache contains precomputed slices of catalog.Column interfaces.
type columnCache struct {
all []catalog.Column
public []catalog.Column
writable []catalog.Column
deletable []catalog.Column
nonDrop []catalog.Column
visible []catalog.Column
accessible []catalog.Column
readable []catalog.Column
withUDTs []catalog.Column
system []catalog.Column
familyDefaultColumns []fetchpb.IndexFetchSpec_FamilyDefaultColumn
index []indexColumnCache
}
type indexColumnCache struct {
all []catalog.Column
allDirs []catenumpb.IndexColumn_Direction
key []catalog.Column
keyDirs []catenumpb.IndexColumn_Direction
stored []catalog.Column
keySuffix []catalog.Column
full []catalog.Column
fullDirs []catenumpb.IndexColumn_Direction
keyAndSuffix []fetchpb.IndexFetchSpec_KeyColumn
}
// newColumnCache returns a fresh fully-populated columnCache struct for the
// TableDescriptor.
func newColumnCache(desc *descpb.TableDescriptor, mutations *mutationCache) *columnCache {
c := columnCache{}
// Build a slice of structs to back the public and system interfaces in c.all.
// This is better than allocating memory once per struct.
numPublic := len(desc.Columns)
backingStructs := make([]column, numPublic, numPublic+len(colinfo.AllSystemColumnDescs))
for i := range desc.Columns {
backingStructs[i] = column{desc: &desc.Columns[i], ordinal: i}
}
numMutations := len(mutations.columns)
numDeletable := numPublic + numMutations
for i := range colinfo.AllSystemColumnDescs {
col := column{
desc: &colinfo.AllSystemColumnDescs[i],
ordinal: numDeletable + i,
}
backingStructs = append(backingStructs, col)
}
// Populate the c.all slice with Column interfaces.
c.all = make([]catalog.Column, 0, numDeletable+len(colinfo.AllSystemColumnDescs))
for i := range backingStructs[:numPublic] {
c.all = append(c.all, &backingStructs[i])
}
for _, m := range mutations.columns {
c.all = append(c.all, m.AsColumn())
}
for i := range backingStructs[numPublic:] {
c.all = append(c.all, &backingStructs[numPublic+i])
}
// Populate the remaining column slice fields.
c.deletable = c.all[:numDeletable]
c.system = c.all[numDeletable:]
c.public = c.all[:numPublic]
if numMutations == 0 {
c.readable = c.public
c.writable = c.public
c.nonDrop = c.public
} else {
for _, col := range c.deletable {
if !col.DeleteOnly() {
lazyAllocAppendColumn(&c.writable, col, numDeletable)
}
if !col.Dropped() {
lazyAllocAppendColumn(&c.nonDrop, col, numDeletable)
}
lazyAllocAppendColumn(&c.readable, col, numDeletable)
}
}
for _, col := range c.deletable {
if col.Public() && !col.IsHidden() && !col.IsInaccessible() {
lazyAllocAppendColumn(&c.visible, col, numPublic)
}
if col.Public() && !col.IsInaccessible() {
lazyAllocAppendColumn(&c.accessible, col, numPublic)
}
if col.HasType() && col.GetType().UserDefined() {
lazyAllocAppendColumn(&c.withUDTs, col, numDeletable)
}
}
// Populate familyDefaultColumns.
for i := range desc.Families {
if f := &desc.Families[i]; f.DefaultColumnID != 0 {
if c.familyDefaultColumns == nil {
c.familyDefaultColumns = make([]fetchpb.IndexFetchSpec_FamilyDefaultColumn, 0, len(desc.Families)-i)
}
c.familyDefaultColumns = append(c.familyDefaultColumns, fetchpb.IndexFetchSpec_FamilyDefaultColumn{
FamilyID: f.ID,
DefaultColumnID: f.DefaultColumnID,
})
}
}
// Populate the per-index column cache
c.index = make([]indexColumnCache, 0, 1+len(desc.Indexes)+len(mutations.indexes))
c.index = append(c.index, makeIndexColumnCache(&desc.PrimaryIndex, c.all))
for i := range desc.Indexes {
c.index = append(c.index, makeIndexColumnCache(&desc.Indexes[i], c.all))
}
for i := range mutations.indexes {
c.index = append(c.index, makeIndexColumnCache(mutations.indexes[i].AsIndex().IndexDesc(), c.all))
}
return &c
}
// makeIndexColumnCache builds a cache of catalog.Column slices pertaining to
// the columns referenced in an index.
func makeIndexColumnCache(idx *descpb.IndexDescriptor, all []catalog.Column) (ic indexColumnCache) {
nKey := len(idx.KeyColumnIDs)
nKeySuffix := len(idx.KeySuffixColumnIDs)
nStored := len(idx.StoreColumnIDs)
nAll := nKey + nKeySuffix + nStored
ic.allDirs = make([]catenumpb.IndexColumn_Direction, nAll)
// Only copy key column directions, others will remain at ASC (default value).
copy(ic.allDirs, idx.KeyColumnDirections)
ic.all = make([]catalog.Column, 0, nAll)
appendColumnsByID(&ic.all, all, idx.KeyColumnIDs)
appendColumnsByID(&ic.all, all, idx.KeySuffixColumnIDs)
appendColumnsByID(&ic.all, all, idx.StoreColumnIDs)
ic.key = ic.all[:nKey]
ic.keyDirs = ic.allDirs[:nKey]
ic.keySuffix = ic.all[nKey : nKey+nKeySuffix]
ic.stored = ic.all[nKey+nKeySuffix:]
nFull := nKey
if !idx.Unique {
nFull = nFull + nKeySuffix
}
ic.full = ic.all[:nFull]
ic.fullDirs = ic.allDirs[:nFull]
// Populate keyAndSuffix. Note that this method can be called on an incomplete
// (mutable) descriptor (e.g. as part of initializing a new descriptor); this
// code needs to tolerate any descriptor state (like having no key columns, or
// having uninitialized column IDs).
var invertedColumnID descpb.ColumnID
if nKey > 0 && idx.Type == descpb.IndexDescriptor_INVERTED {
invertedColumnID = idx.InvertedColumnID()
}
var compositeIDs catalog.TableColSet
for _, colID := range idx.CompositeColumnIDs {
compositeIDs.Add(colID)
}
ic.keyAndSuffix = make([]fetchpb.IndexFetchSpec_KeyColumn, nKey+nKeySuffix)
for i := range ic.keyAndSuffix {
col := ic.all[i]
if col == nil {
ic.keyAndSuffix[i].Name = "invalid"
continue
}
colID := col.GetID()
typ := col.GetType()
if colID != 0 && colID == invertedColumnID {
typ = idx.InvertedColumnKeyType()
}
ic.keyAndSuffix[i] = fetchpb.IndexFetchSpec_KeyColumn{
IndexFetchSpec_Column: fetchpb.IndexFetchSpec_Column{
Name: col.GetName(),
ColumnID: colID,
Type: typ,
IsNonNullable: !col.IsNullable(),
},
Direction: ic.allDirs[i],
IsComposite: compositeIDs.Contains(colID),
IsInverted: colID == invertedColumnID,
}
}
return ic
}
func appendColumnsByID(slice *[]catalog.Column, source []catalog.Column, ids []descpb.ColumnID) {
for _, id := range ids {
var col catalog.Column
for _, candidate := range source {
if candidate.GetID() == id {
col = candidate
break
}
}
*slice = append(*slice, col)
}
}
func lazyAllocAppendColumn(slice *[]catalog.Column, col catalog.Column, cap int) {
if *slice == nil {
*slice = make([]catalog.Column, 0, cap)
}
*slice = append(*slice, col)
}