@@ -50,6 +50,12 @@ type KeyspaceMetadata struct {
50
50
UserTypes map [string ]* UserTypeMetadata
51
51
}
52
52
53
+ // schema metadata for a virtual keyspace
54
+ type VirtualKeyspaceMetadata struct {
55
+ Name string
56
+ Tables map [string ]* VirtualTableMetadata
57
+ }
58
+
53
59
// schema metadata for a table (a.k.a. column family)
54
60
type TableMetadata struct {
55
61
Keyspace string
@@ -66,6 +72,13 @@ type TableMetadata struct {
66
72
OrderedColumns []string
67
73
}
68
74
75
+ type VirtualTableMetadata struct {
76
+ Keyspace string
77
+ Name string
78
+ Comment string
79
+ Columns map [string ]* VirtualColumnMetadata
80
+ }
81
+
69
82
// schema metadata for a column
70
83
type ColumnMetadata struct {
71
84
Keyspace string
@@ -80,6 +93,15 @@ type ColumnMetadata struct {
80
93
Index ColumnIndexMetadata
81
94
}
82
95
96
+ type VirtualColumnMetadata struct {
97
+ Keyspace string
98
+ Table string
99
+ Name string
100
+ ClusteringOrder string
101
+ Kind ColumnKind
102
+ Type TypeInfo
103
+ }
104
+
83
105
// FunctionMetadata holds metadata for function constructs
84
106
type FunctionMetadata struct {
85
107
Keyspace string
@@ -231,6 +253,13 @@ type schemaDescriber struct {
231
253
cache map [string ]* KeyspaceMetadata
232
254
}
233
255
256
+ // queries the cluster for schema information for a virtual keyspace
257
+ type virtualSchemaDescriber struct {
258
+ session * Session
259
+ mu sync.Mutex
260
+ cache map [string ]* VirtualKeyspaceMetadata
261
+ }
262
+
234
263
// creates a session bound schema describer which will query and cache
235
264
// keyspace metadata
236
265
func newSchemaDescriber (session * Session ) * schemaDescriber {
@@ -240,6 +269,15 @@ func newSchemaDescriber(session *Session) *schemaDescriber {
240
269
}
241
270
}
242
271
272
+ // creates a session bound schema describer which will query and cache
273
+ // virtual keyspace metadata
274
+ func newVirtualSchemaDescriber (session * Session ) * virtualSchemaDescriber {
275
+ return & virtualSchemaDescriber {
276
+ session : session ,
277
+ cache : map [string ]* VirtualKeyspaceMetadata {},
278
+ }
279
+ }
280
+
243
281
// returns the cached KeyspaceMetadata held by the describer for the named
244
282
// keyspace.
245
283
func (s * schemaDescriber ) getSchema (keyspaceName string ) (* KeyspaceMetadata , error ) {
@@ -260,6 +298,23 @@ func (s *schemaDescriber) getSchema(keyspaceName string) (*KeyspaceMetadata, err
260
298
return metadata , nil
261
299
}
262
300
301
+ // returns the cached VirtualKeyspaceMetadata held by the describer for the named
302
+ // keyspace.
303
+ func (s * virtualSchemaDescriber ) getSchema (keyspaceName string ) (* VirtualKeyspaceMetadata , error ) {
304
+ s .mu .Lock ()
305
+ defer s .mu .Unlock ()
306
+ metadata , found := s .cache [keyspaceName ]
307
+ if ! found {
308
+ err := s .refreshSchema (keyspaceName )
309
+ if err != nil {
310
+ return nil , err
311
+ }
312
+ metadata = s .cache [keyspaceName ]
313
+ }
314
+
315
+ return metadata , nil
316
+ }
317
+
263
318
// clears the already cached keyspace metadata
264
319
func (s * schemaDescriber ) clearSchema (keyspaceName string ) {
265
320
s .mu .Lock ()
@@ -314,6 +369,43 @@ func (s *schemaDescriber) refreshSchema(keyspaceName string) error {
314
369
return nil
315
370
}
316
371
372
+ // forcibly updates the current VirtualKeyspaceMetadata held by the virtual schema describer
373
+ // for a given named keyspace.
374
+ func (s * virtualSchemaDescriber ) refreshSchema (keyspaceName string ) error {
375
+ var wg sync.WaitGroup
376
+
377
+ var (
378
+ tables []VirtualTableMetadata
379
+ columns []VirtualColumnMetadata
380
+ tableErr , columnErr error
381
+ )
382
+
383
+ wg .Add (2 )
384
+ go func () {
385
+ defer wg .Done ()
386
+ tables , tableErr = getVirtualTableMetadata (s .session , keyspaceName )
387
+ }()
388
+ go func () {
389
+ defer wg .Done ()
390
+ columns , columnErr = getVirtualColumnMetadata (s .session , keyspaceName )
391
+ }()
392
+ wg .Wait ()
393
+
394
+ if columnErr != nil {
395
+ return columnErr
396
+ }
397
+ if tableErr != nil {
398
+ return tableErr
399
+ }
400
+
401
+ keyspaceMetadata := & VirtualKeyspaceMetadata {Name : keyspaceName }
402
+ compileVirtualMetadata (keyspaceMetadata , tables , columns )
403
+
404
+ s .cache [keyspaceName ] = keyspaceMetadata
405
+
406
+ return nil
407
+ }
408
+
317
409
// "compiles" derived information about keyspace, table, and column metadata
318
410
// for a keyspace from the basic queried metadata objects returned by
319
411
// getKeyspaceMetadata, getTableMetadata, and getColumnMetadata respectively;
@@ -395,6 +487,33 @@ func compileMetadata(
395
487
}
396
488
}
397
489
490
+ // "compiles" derived information about virtual keyspace, table, and column metadata
491
+ // for a keyspace from the basic queried metadata objects returned by
492
+ // getVirtualTableMetadata, and getVirtualColumnMetadata respectively;
493
+ // Links the metadata objects together.
494
+ func compileVirtualMetadata (
495
+ keyspace * VirtualKeyspaceMetadata ,
496
+ tables []VirtualTableMetadata ,
497
+ columns []VirtualColumnMetadata ,
498
+ ) {
499
+ keyspace .Tables = make (map [string ]* VirtualTableMetadata )
500
+ for i := range tables {
501
+ tables [i ].Columns = make (map [string ]* VirtualColumnMetadata )
502
+
503
+ keyspace .Tables [tables [i ].Name ] = & tables [i ]
504
+ }
505
+
506
+ for i := range columns {
507
+ col := & columns [i ]
508
+ table , ok := keyspace .Tables [col .Table ]
509
+ if ! ok {
510
+ continue
511
+ }
512
+
513
+ table .Columns [col .Name ] = col
514
+ }
515
+ }
516
+
398
517
// Compiles derived information from TableMetadata which have had
399
518
// ColumnMetadata added already. V1 protocol does not return as much
400
519
// column metadata as V2+ (because V1 doesn't support the "type" column in the
@@ -738,6 +857,37 @@ func getTableMetadata(session *Session, keyspaceName string) ([]TableMetadata, e
738
857
return tables , nil
739
858
}
740
859
860
+ // query for only the table metadata in the specified keyspace from system_virtual_schema.tables
861
+ func getVirtualTableMetadata (s * Session , keyspaceName string ) ([]VirtualTableMetadata , error ) {
862
+ const stmt = `
863
+ SELECT
864
+ table_name,
865
+ comment
866
+ FROM system_virtual_schema.tables
867
+ WHERE keyspace_name = ?`
868
+
869
+ tables := []VirtualTableMetadata {}
870
+ table := VirtualTableMetadata {Keyspace : keyspaceName }
871
+
872
+ iter := s .control .query (stmt , keyspaceName )
873
+ defer iter .Close ()
874
+
875
+ if iter .err != nil {
876
+ return nil , fmt .Errorf ("failed to iterate virtual table metadata for keyspace: %w" , iter .err )
877
+ }
878
+
879
+ if iter .NumRows () == 0 {
880
+ return nil , ErrKeyspaceDoesNotExist
881
+ }
882
+
883
+ for iter .Scan (& table .Name , & table .Comment ) {
884
+ tables = append (tables , table )
885
+ table = VirtualTableMetadata {Keyspace : keyspaceName }
886
+ }
887
+
888
+ return tables , nil
889
+ }
890
+
741
891
func (s * Session ) scanColumnMetadataV1 (keyspace string ) ([]ColumnMetadata , error ) {
742
892
// V1 does not support the type column, and all returned rows are
743
893
// of kind "regular".
@@ -925,6 +1075,52 @@ func getColumnMetadata(session *Session, keyspaceName string) ([]ColumnMetadata,
925
1075
return columns , nil
926
1076
}
927
1077
1078
+ // query for only the column metadata in the specified keyspace from system_virtual_schema.columns
1079
+ func getVirtualColumnMetadata (s * Session , keyspaceName string ) ([]VirtualColumnMetadata , error ) {
1080
+ const stmt = `
1081
+ SELECT
1082
+ table_name,
1083
+ column_name,
1084
+ clustering_order,
1085
+ kind,
1086
+ type
1087
+ FROM system_virtual_schema.columns
1088
+ WHERE keyspace_name = ?`
1089
+
1090
+ var columns []VirtualColumnMetadata
1091
+
1092
+ rows := s .control .query (stmt , keyspaceName ).Scanner ()
1093
+
1094
+ for rows .Next () {
1095
+ var (
1096
+ column = VirtualColumnMetadata {Keyspace : keyspaceName }
1097
+ columnType string
1098
+ )
1099
+
1100
+ err := rows .Scan (
1101
+ & column .Table ,
1102
+ & column .Name ,
1103
+ & column .ClusteringOrder ,
1104
+ & column .Kind ,
1105
+ & columnType ,
1106
+ )
1107
+
1108
+ if err != nil {
1109
+ return nil , err
1110
+ }
1111
+
1112
+ column .Type = getCassandraType (columnType , s .logger )
1113
+
1114
+ columns = append (columns , column )
1115
+ }
1116
+
1117
+ if err := rows .Err (); err != nil {
1118
+ return nil , fmt .Errorf ("failed to iterate virtual column metadata for keyspace: %w" , err )
1119
+ }
1120
+
1121
+ return columns , nil
1122
+ }
1123
+
928
1124
func getTypeInfo (t string , logger StdLogger ) TypeInfo {
929
1125
if strings .HasPrefix (t , apacheCassandraTypePrefix ) {
930
1126
t = apacheToCassandraType (t )
0 commit comments