@@ -639,6 +639,14 @@ class KeyspaceMetadata(object):
639
639
A dict mapping view names to :class:`.MaterializedViewMetadata` instances.
640
640
"""
641
641
642
+ virtual = False
643
+ """
644
+ A boolean indicating if this is a virtual keyspace or not. Always ``False``
645
+ for clusters running pre-4.0 versions of Cassandra.
646
+
647
+ .. versionadded:: 3.15
648
+ """
649
+
642
650
_exc_info = None
643
651
""" set if metadata parsing failed """
644
652
@@ -671,13 +679,20 @@ def export_as_string(self):
671
679
ret += line
672
680
ret += "\n Approximate structure, for reference:\n (this should not be used to reproduce this schema)\n \n %s\n */" % cql
673
681
return ret
682
+ if self .virtual :
683
+ return ("/*\n Warning: Keyspace {ks} is a virtual keyspace and cannot be recreated with CQL.\n "
684
+ "Structure, for reference:*/\n "
685
+ "{cql}\n "
686
+ "" ).format (ks = self .name , cql = cql )
674
687
return cql
675
688
676
689
def as_cql_query (self ):
677
690
"""
678
691
Returns a CQL query string that can be used to recreate just this keyspace,
679
692
not including user-defined types and tables.
680
693
"""
694
+ if self .virtual :
695
+ return "// VIRTUAL KEYSPACE {}" .format (protect_name (self .name ))
681
696
ret = "CREATE KEYSPACE %s WITH replication = %s " % (
682
697
protect_name (self .name ),
683
698
self .replication_strategy .export_for_schema ())
@@ -1065,11 +1080,21 @@ def primary_key(self):
1065
1080
_exc_info = None
1066
1081
""" set if metadata parsing failed """
1067
1082
1083
+ virtual = False
1084
+ """
1085
+ A boolean indicating if this is a virtual table or not. Always ``False``
1086
+ for clusters running pre-4.0 versions of Cassandra.
1087
+
1088
+ .. versionadded:: 3.15
1089
+ """
1090
+
1068
1091
@property
1069
1092
def is_cql_compatible (self ):
1070
1093
"""
1071
1094
A boolean indicating if this table can be represented as CQL in export
1072
1095
"""
1096
+ if self .virtual :
1097
+ return False
1073
1098
comparator = getattr (self , 'comparator' , None )
1074
1099
if comparator :
1075
1100
# no compact storage with more than one column beyond PK if there
@@ -1086,7 +1111,7 @@ def is_cql_compatible(self):
1086
1111
Metadata describing configuration for table extensions
1087
1112
"""
1088
1113
1089
- def __init__ (self , keyspace_name , name , partition_key = None , clustering_key = None , columns = None , triggers = None , options = None ):
1114
+ def __init__ (self , keyspace_name , name , partition_key = None , clustering_key = None , columns = None , triggers = None , options = None , virtual = False ):
1090
1115
self .keyspace_name = keyspace_name
1091
1116
self .name = name
1092
1117
self .partition_key = [] if partition_key is None else partition_key
@@ -1097,6 +1122,7 @@ def __init__(self, keyspace_name, name, partition_key=None, clustering_key=None,
1097
1122
self .comparator = None
1098
1123
self .triggers = OrderedDict () if triggers is None else triggers
1099
1124
self .views = {}
1125
+ self .virtual = virtual
1100
1126
1101
1127
def export_as_string (self ):
1102
1128
"""
@@ -1116,6 +1142,11 @@ def export_as_string(self):
1116
1142
ret = "/*\n Warning: Table %s.%s omitted because it has constructs not compatible with CQL (was created via legacy API).\n " % \
1117
1143
(self .keyspace_name , self .name )
1118
1144
ret += "\n Approximate structure, for reference:\n (this should not be used to reproduce this schema)\n \n %s\n */" % self ._all_as_cql ()
1145
+ elif self .virtual :
1146
+ ret = ('/*\n Warning: Table {ks}.{tab} is a virtual table and cannot be recreated with CQL.\n '
1147
+ 'Structure, for reference:\n '
1148
+ '{cql}\n */' ).format (ks = self .keyspace_name , tab = self .name , cql = self ._all_as_cql ())
1149
+
1119
1150
else :
1120
1151
ret = self ._all_as_cql ()
1121
1152
@@ -1150,7 +1181,8 @@ def as_cql_query(self, formatted=False):
1150
1181
creations are not included). If `formatted` is set to :const:`True`,
1151
1182
extra whitespace will be added to make the query human readable.
1152
1183
"""
1153
- ret = "CREATE TABLE %s.%s (%s" % (
1184
+ ret = "%s TABLE %s.%s (%s" % (
1185
+ ('VIRTUAL' if self .virtual else 'CREATE' ),
1154
1186
protect_name (self .keyspace_name ),
1155
1187
protect_name (self .name ),
1156
1188
"\n " if formatted else "" )
@@ -2245,28 +2277,32 @@ def _build_aggregate(aggregate_row):
2245
2277
aggregate_row ['argument_types' ], aggregate_row ['state_func' ], aggregate_row ['state_type' ],
2246
2278
aggregate_row ['final_func' ], aggregate_row ['initcond' ], aggregate_row ['return_type' ])
2247
2279
2248
- def _build_table_metadata (self , row , col_rows = None , trigger_rows = None , index_rows = None ):
2280
+ def _build_table_metadata (self , row , col_rows = None , trigger_rows = None , index_rows = None , virtual = False ):
2249
2281
keyspace_name = row ["keyspace_name" ]
2250
2282
table_name = row [self ._table_name_col ]
2251
2283
2252
2284
col_rows = col_rows or self .keyspace_table_col_rows [keyspace_name ][table_name ]
2253
2285
trigger_rows = trigger_rows or self .keyspace_table_trigger_rows [keyspace_name ][table_name ]
2254
2286
index_rows = index_rows or self .keyspace_table_index_rows [keyspace_name ][table_name ]
2255
2287
2256
- table_meta = TableMetadataV3 (keyspace_name , table_name )
2288
+ table_meta = TableMetadataV3 (keyspace_name , table_name , virtual = virtual )
2257
2289
try :
2258
2290
table_meta .options = self ._build_table_options (row )
2259
2291
flags = row .get ('flags' , set ())
2260
2292
if flags :
2261
2293
compact_static = False
2262
2294
table_meta .is_compact_storage = 'dense' in flags or 'super' in flags or 'compound' not in flags
2263
2295
is_dense = 'dense' in flags
2296
+ elif virtual :
2297
+ compact_static = False
2298
+ table_meta .is_compact_storage = False
2299
+ is_dense = False
2264
2300
else :
2265
2301
compact_static = True
2266
2302
table_meta .is_compact_storage = True
2267
2303
is_dense = False
2268
2304
2269
- self ._build_table_columns (table_meta , col_rows , compact_static , is_dense )
2305
+ self ._build_table_columns (table_meta , col_rows , compact_static , is_dense , virtual )
2270
2306
2271
2307
for trigger_row in trigger_rows :
2272
2308
trigger_meta = self ._build_trigger_metadata (table_meta , trigger_row )
@@ -2288,7 +2324,7 @@ def _build_table_options(self, row):
2288
2324
""" Setup the mostly-non-schema table options, like caching settings """
2289
2325
return dict ((o , row .get (o )) for o in self .recognized_table_options if o in row )
2290
2326
2291
- def _build_table_columns (self , meta , col_rows , compact_static = False , is_dense = False ):
2327
+ def _build_table_columns (self , meta , col_rows , compact_static = False , is_dense = False , virtual = False ):
2292
2328
# partition key
2293
2329
partition_rows = [r for r in col_rows
2294
2330
if r .get ('kind' , None ) == "partition_key" ]
@@ -2432,6 +2468,116 @@ class SchemaParserV4(SchemaParserV3):
2432
2468
)
2433
2469
)
2434
2470
2471
+ _SELECT_VIRTUAL_KEYSPACES = 'SELECT * from system_virtual_schema.keyspaces'
2472
+ _SELECT_VIRTUAL_TABLES = 'SELECT * from system_virtual_schema.tables'
2473
+ _SELECT_VIRTUAL_COLUMNS = 'SELECT * from system_virtual_schema.columns'
2474
+
2475
+ def __init__ (self , connection , timeout ):
2476
+ super (SchemaParserV4 , self ).__init__ (connection , timeout )
2477
+ self .virtual_keyspaces_rows = defaultdict (list )
2478
+ self .virtual_tables_rows = defaultdict (list )
2479
+ self .virtual_columns_rows = defaultdict (lambda : defaultdict (list ))
2480
+
2481
+ def _query_all (self ):
2482
+ cl = ConsistencyLevel .ONE
2483
+ # todo: this duplicates V3; we should find a way for _query_all methods
2484
+ # to extend each other.
2485
+ queries = [
2486
+ # copied from V3
2487
+ QueryMessage (query = self ._SELECT_KEYSPACES , consistency_level = cl ),
2488
+ QueryMessage (query = self ._SELECT_TABLES , consistency_level = cl ),
2489
+ QueryMessage (query = self ._SELECT_COLUMNS , consistency_level = cl ),
2490
+ QueryMessage (query = self ._SELECT_TYPES , consistency_level = cl ),
2491
+ QueryMessage (query = self ._SELECT_FUNCTIONS , consistency_level = cl ),
2492
+ QueryMessage (query = self ._SELECT_AGGREGATES , consistency_level = cl ),
2493
+ QueryMessage (query = self ._SELECT_TRIGGERS , consistency_level = cl ),
2494
+ QueryMessage (query = self ._SELECT_INDEXES , consistency_level = cl ),
2495
+ QueryMessage (query = self ._SELECT_VIEWS , consistency_level = cl ),
2496
+ # V4-only queries
2497
+ QueryMessage (query = self ._SELECT_VIRTUAL_KEYSPACES , consistency_level = cl ),
2498
+ QueryMessage (query = self ._SELECT_VIRTUAL_TABLES , consistency_level = cl ),
2499
+ QueryMessage (query = self ._SELECT_VIRTUAL_COLUMNS , consistency_level = cl )
2500
+ ]
2501
+
2502
+ responses = self .connection .wait_for_responses (
2503
+ * queries , timeout = self .timeout , fail_on_error = False )
2504
+ (
2505
+ # copied from V3
2506
+ (ks_success , ks_result ),
2507
+ (table_success , table_result ),
2508
+ (col_success , col_result ),
2509
+ (types_success , types_result ),
2510
+ (functions_success , functions_result ),
2511
+ (aggregates_success , aggregates_result ),
2512
+ (triggers_success , triggers_result ),
2513
+ (indexes_success , indexes_result ),
2514
+ (views_success , views_result ),
2515
+ # V4-only responses
2516
+ (virtual_ks_success , virtual_ks_result ),
2517
+ (virtual_table_success , virtual_table_result ),
2518
+ (virtual_column_success , virtual_column_result )
2519
+ ) = responses
2520
+
2521
+ # copied from V3
2522
+ self .keyspaces_result = self ._handle_results (ks_success , ks_result )
2523
+ self .tables_result = self ._handle_results (table_success , table_result )
2524
+ self .columns_result = self ._handle_results (col_success , col_result )
2525
+ self .triggers_result = self ._handle_results (triggers_success , triggers_result )
2526
+ self .types_result = self ._handle_results (types_success , types_result )
2527
+ self .functions_result = self ._handle_results (functions_success , functions_result )
2528
+ self .aggregates_result = self ._handle_results (aggregates_success , aggregates_result )
2529
+ self .indexes_result = self ._handle_results (indexes_success , indexes_result )
2530
+ self .views_result = self ._handle_results (views_success , views_result )
2531
+ # V4-only results
2532
+ self .virtual_keyspaces_result = self ._handle_results (virtual_ks_success ,
2533
+ virtual_ks_result )
2534
+ self .virtual_tables_result = self ._handle_results (virtual_table_success ,
2535
+ virtual_table_result )
2536
+ self .virtual_columns_result = self ._handle_results (virtual_column_success ,
2537
+ virtual_column_result )
2538
+ self ._aggregate_results ()
2539
+
2540
+ def _aggregate_results (self ):
2541
+ super (SchemaParserV4 , self )._aggregate_results ()
2542
+
2543
+ m = self .virtual_tables_rows
2544
+ for row in self .virtual_tables_result :
2545
+ m [row ["keyspace_name" ]].append (row )
2546
+
2547
+ m = self .virtual_columns_rows
2548
+ for row in self .virtual_columns_result :
2549
+ ks_name = row ['keyspace_name' ]
2550
+ tab_name = row [self ._table_name_col ]
2551
+ m [ks_name ][tab_name ].append (row )
2552
+
2553
+ def get_all_keyspaces (self ):
2554
+ for x in super (SchemaParserV4 , self ).get_all_keyspaces ():
2555
+ yield x
2556
+
2557
+ for row in self .virtual_keyspaces_result :
2558
+ ks_name = row ['keyspace_name' ]
2559
+ keyspace_meta = self ._build_keyspace_metadata (row )
2560
+ keyspace_meta .virtual = True
2561
+
2562
+ for table_row in self .virtual_tables_rows .get (ks_name , []):
2563
+ table_name = table_row [self ._table_name_col ]
2564
+
2565
+ col_rows = self .virtual_columns_rows [ks_name ][table_name ]
2566
+ keyspace_meta ._add_table_metadata (
2567
+ self ._build_table_metadata (table_row ,
2568
+ col_rows = col_rows ,
2569
+ virtual = True )
2570
+ )
2571
+ yield keyspace_meta
2572
+
2573
+ @staticmethod
2574
+ def _build_keyspace_metadata_internal (row ):
2575
+ # necessary fields that aren't int virtual ks
2576
+ row ["durable_writes" ] = row .get ("durable_writes" , None )
2577
+ row ["replication" ] = row .get ("replication" , {})
2578
+ row ["replication" ]["class" ] = row ["replication" ].get ("class" , None )
2579
+ return super (SchemaParserV4 , SchemaParserV4 )._build_keyspace_metadata_internal (row )
2580
+
2435
2581
2436
2582
class TableMetadataV3 (TableMetadata ):
2437
2583
compaction_options = {}
0 commit comments