@@ -52,6 +52,12 @@ type KeyspaceMetadata struct {
5252 UserTypes map [string ]* UserTypeMetadata
5353}
5454
55+ // schema metadata for a virtual keyspace
56+ type VirtualKeyspaceMetadata struct {
57+ Name string
58+ Tables map [string ]* VirtualTableMetadata
59+ }
60+
5561// schema metadata for a table (a.k.a. column family)
5662type TableMetadata struct {
5763 Keyspace string
@@ -68,6 +74,13 @@ type TableMetadata struct {
6874 OrderedColumns []string
6975}
7076
77+ type VirtualTableMetadata struct {
78+ Keyspace string
79+ Name string
80+ Comment string
81+ Columns map [string ]* VirtualColumnMetadata
82+ }
83+
7184// schema metadata for a column
7285type ColumnMetadata struct {
7386 Keyspace string
@@ -82,6 +95,15 @@ type ColumnMetadata struct {
8295 Index ColumnIndexMetadata
8396}
8497
98+ type VirtualColumnMetadata struct {
99+ Keyspace string
100+ Table string
101+ Name string
102+ ClusteringOrder string
103+ Kind ColumnKind
104+ Type TypeInfo
105+ }
106+
85107// FunctionMetadata holds metadata for function constructs
86108type FunctionMetadata struct {
87109 Keyspace string
@@ -240,6 +262,13 @@ type schemaDescriber struct {
240262 cache map [string ]* KeyspaceMetadata
241263}
242264
265+ // queries the cluster for schema information for a virtual keyspace
266+ type virtualSchemaDescriber struct {
267+ session * Session
268+ mu sync.Mutex
269+ cache map [string ]* VirtualKeyspaceMetadata
270+ }
271+
243272// creates a session bound schema describer which will query and cache
244273// keyspace metadata
245274func newSchemaDescriber (session * Session ) * schemaDescriber {
@@ -249,6 +278,15 @@ func newSchemaDescriber(session *Session) *schemaDescriber {
249278 }
250279}
251280
281+ // creates a session bound schema describer which will query and cache
282+ // virtual keyspace metadata
283+ func newVirtualSchemaDescriber (session * Session ) * virtualSchemaDescriber {
284+ return & virtualSchemaDescriber {
285+ session : session ,
286+ cache : map [string ]* VirtualKeyspaceMetadata {},
287+ }
288+ }
289+
252290// returns the cached KeyspaceMetadata held by the describer for the named
253291// keyspace.
254292func (s * schemaDescriber ) getSchema (keyspaceName string ) (* KeyspaceMetadata , error ) {
@@ -269,6 +307,23 @@ func (s *schemaDescriber) getSchema(keyspaceName string) (*KeyspaceMetadata, err
269307 return metadata , nil
270308}
271309
310+ // returns the cached VirtualKeyspaceMetadata held by the describer for the named
311+ // keyspace.
312+ func (s * virtualSchemaDescriber ) getSchema (keyspaceName string ) (* VirtualKeyspaceMetadata , error ) {
313+ s .mu .Lock ()
314+ defer s .mu .Unlock ()
315+ metadata , found := s .cache [keyspaceName ]
316+ if ! found {
317+ err := s .refreshSchema (keyspaceName )
318+ if err != nil {
319+ return nil , err
320+ }
321+ metadata = s .cache [keyspaceName ]
322+ }
323+
324+ return metadata , nil
325+ }
326+
272327// clears the already cached keyspace metadata
273328func (s * schemaDescriber ) clearSchema (keyspaceName string ) {
274329 s .mu .Lock ()
@@ -323,6 +378,42 @@ func (s *schemaDescriber) refreshSchema(keyspaceName string) error {
323378 return nil
324379}
325380
381+ // forcibly updates the current VirtualKeyspaceMetadata held by the virtual schema describer
382+ // for a given named keyspace.
383+ func (s * virtualSchemaDescriber ) refreshSchema (keyspaceName string ) error {
384+ var wg sync.WaitGroup
385+ var tables []VirtualTableMetadata
386+ var columns []VirtualColumnMetadata
387+ var err error
388+
389+ wg .Add (2 )
390+ go func () {
391+ defer wg .Done ()
392+ tables , err = getVirtualTableMetadata (s .session , keyspaceName )
393+ if err != nil {
394+ return
395+ }
396+ }()
397+ go func () {
398+ defer wg .Done ()
399+ columns , err = getVirtualColumnMetadata (s .session , keyspaceName )
400+ if err != nil {
401+ return
402+ }
403+ }()
404+ wg .Wait ()
405+ if err != nil {
406+ return err
407+ }
408+
409+ keyspaceMetadata := & VirtualKeyspaceMetadata {Name : keyspaceName }
410+ compileVirtualMetadata (keyspaceMetadata , tables , columns )
411+
412+ s .cache [keyspaceName ] = keyspaceMetadata
413+
414+ return nil
415+ }
416+
326417// "compiles" derived information about keyspace, table, and column metadata
327418// for a keyspace from the basic queried metadata objects returned by
328419// getKeyspaceMetadata, getTableMetadata, and getColumnMetadata respectively;
@@ -417,6 +508,33 @@ func compileMetadata(
417508 }
418509}
419510
511+ // "compiles" derived information about virtual keyspace, table, and column metadata
512+ // for a keyspace from the basic queried metadata objects returned by
513+ // getVirtualTableMetadata, and getVirtualColumnMetadata respectively;
514+ // Links the metadata objects together.
515+ func compileVirtualMetadata (
516+ keyspace * VirtualKeyspaceMetadata ,
517+ tables []VirtualTableMetadata ,
518+ columns []VirtualColumnMetadata ,
519+ ) {
520+ keyspace .Tables = make (map [string ]* VirtualTableMetadata )
521+ for i := range tables {
522+ tables [i ].Columns = make (map [string ]* VirtualColumnMetadata )
523+
524+ keyspace .Tables [tables [i ].Name ] = & tables [i ]
525+ }
526+
527+ for i := range columns {
528+ col := & columns [i ]
529+ table , ok := keyspace .Tables [col .Table ]
530+ if ! ok {
531+ continue
532+ }
533+
534+ table .Columns [col .Name ] = col
535+ }
536+ }
537+
420538// Compiles derived information from TableMetadata which have had
421539// ColumnMetadata added already. V1 protocol does not return as much
422540// column metadata as V2+ (because V1 doesn't support the "type" column in the
@@ -760,6 +878,28 @@ func getTableMetadata(session *Session, keyspaceName string) ([]TableMetadata, e
760878 return tables , nil
761879}
762880
881+ // query for only the table metadata in the specified keyspace from system_virtual_schema.tables
882+ func getVirtualTableMetadata (s * Session , keyspaceName string ) ([]VirtualTableMetadata , error ) {
883+ const stmt = `
884+ SELECT
885+ table_name,
886+ comment
887+ FROM system_virtual_schema.tables
888+ WHERE keyspace_name = ?`
889+
890+ tables := []VirtualTableMetadata {}
891+ table := VirtualTableMetadata {Keyspace : keyspaceName }
892+
893+ iter := s .control .query (stmt , keyspaceName )
894+
895+ for iter .Scan (& table .Name , & table .Comment ) {
896+ tables = append (tables , table )
897+ table = VirtualTableMetadata {Keyspace : keyspaceName }
898+ }
899+
900+ return tables , nil
901+ }
902+
763903func (s * Session ) scanColumnMetadataV1 (keyspace string ) ([]ColumnMetadata , error ) {
764904 // V1 does not support the type column, and all returned rows are
765905 // of kind "regular".
@@ -947,6 +1087,47 @@ func getColumnMetadata(session *Session, keyspaceName string) ([]ColumnMetadata,
9471087 return columns , nil
9481088}
9491089
1090+ // query for only the column metadata in the specified keyspace from system_virtual_schema.columns
1091+ func getVirtualColumnMetadata (s * Session , keyspaceName string ) ([]VirtualColumnMetadata , error ) {
1092+ const stmt = `
1093+ SELECT
1094+ table_name,
1095+ column_name,
1096+ clustering_order,
1097+ kind,
1098+ type
1099+ FROM system_virtual_schema.columns
1100+ WHERE keyspace_name = ?`
1101+
1102+ var columns []VirtualColumnMetadata
1103+
1104+ rows := s .control .query (stmt , keyspaceName ).Scanner ()
1105+ for rows .Next () {
1106+ var (
1107+ column = VirtualColumnMetadata {Keyspace : keyspaceName }
1108+ columnType string
1109+ )
1110+
1111+ err := rows .Scan (
1112+ & column .Table ,
1113+ & column .Name ,
1114+ & column .ClusteringOrder ,
1115+ & column .Kind ,
1116+ & columnType ,
1117+ )
1118+
1119+ if err != nil {
1120+ return nil , err
1121+ }
1122+
1123+ column .Type = getCassandraType (columnType , s .logger )
1124+
1125+ columns = append (columns , column )
1126+ }
1127+
1128+ return columns , nil
1129+ }
1130+
9501131func getTypeInfo (t string , logger StdLogger ) TypeInfo {
9511132 if strings .HasPrefix (t , apacheCassandraTypePrefix ) {
9521133 t = apacheToCassandraType (t )
0 commit comments