scylla-cqlsh 6.0.30__cp314-cp314-musllinux_1_2_aarch64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,1670 @@
1
+ # Licensed to the Apache Software Foundation (ASF) under one
2
+ # or more contributor license agreements. See the NOTICE file
3
+ # distributed with this work for additional information
4
+ # regarding copyright ownership. The ASF licenses this file
5
+ # to you under the Apache License, Version 2.0 (the
6
+ # "License"); you may not use this file except in compliance
7
+ # with the License. You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
17
+ from cassandra.metadata import maybe_escape_name
18
+ from cqlshlib import helptopics
19
+ from cqlshlib.cqlhandling import CqlParsingRuleSet, Hint
20
+
21
+ simple_cql_types = {'ascii', 'bigint', 'blob', 'boolean', 'counter', 'date', 'decimal', 'double', 'duration', 'float',
22
+ 'inet', 'int', 'smallint', 'text', 'time', 'timestamp', 'timeuuid', 'tinyint', 'uuid', 'varchar',
23
+ 'varint'}
24
+ simple_cql_types.difference_update(('set', 'map', 'list'))
25
+
26
+ cqldocs = helptopics.CQL3HelpTopics()
27
+
28
+
29
+ class UnexpectedTableStructure(UserWarning):
30
+
31
+ def __init__(self, msg):
32
+ self.msg = msg
33
+
34
+ def __str__(self):
35
+ return 'Unexpected table structure; may not translate correctly to CQL. ' + self.msg
36
+
37
+
38
+ SYSTEM_KEYSPACES = ('system', 'system_schema', 'system_traces', 'system_auth', 'system_distributed', 'system_views',
39
+ 'system_virtual_schema', 'system_distributed_everywhere', 'system_replicated_keys')
40
+ NONALTERBALE_KEYSPACES = ('system', 'system_schema', 'system_views', 'system_virtual_schema', 'system_distributed_everywhere', 'system_replicated_keys')
41
+
42
+
43
+ class Cql3ParsingRuleSet(CqlParsingRuleSet):
44
+
45
+ columnfamily_layout_options = (
46
+ ('bloom_filter_fp_chance', None),
47
+ ('comment', None),
48
+ ('gc_grace_seconds', None),
49
+ ('min_index_interval', None),
50
+ ('max_index_interval', None),
51
+ ('default_time_to_live', None),
52
+ ('speculative_retry', None),
53
+ ('additional_write_policy', None),
54
+ ('memtable_flush_period_in_ms', None),
55
+ ('cdc', None),
56
+ ('read_repair', None),
57
+ )
58
+
59
+ columnfamily_layout_map_options = (
60
+ # (CQL3 option name, schema_columnfamilies column name (or None if same),
61
+ # list of known map keys)
62
+ ('compaction', 'compaction_strategy_options',
63
+ ('class', 'max_threshold', 'tombstone_compaction_interval', 'tombstone_threshold', 'enabled',
64
+ 'unchecked_tombstone_compaction', 'only_purge_repaired_tombstones', 'provide_overlapping_tombstones')),
65
+ ('compression', 'compression_parameters',
66
+ ('sstable_compression', 'chunk_length_kb', 'crc_check_chance')),
67
+ ('caching', None,
68
+ ('rows_per_partition', 'keys')),
69
+ )
70
+
71
+ obsolete_cf_options = ()
72
+
73
+ consistency_levels = (
74
+ 'ANY',
75
+ 'ONE',
76
+ 'TWO',
77
+ 'THREE',
78
+ 'QUORUM',
79
+ 'ALL',
80
+ 'LOCAL_QUORUM',
81
+ 'EACH_QUORUM',
82
+ 'SERIAL'
83
+ )
84
+
85
+ size_tiered_compaction_strategy_options = (
86
+ 'min_sstable_size',
87
+ 'min_threshold',
88
+ 'bucket_high',
89
+ 'bucket_low'
90
+ )
91
+
92
+ leveled_compaction_strategy_options = (
93
+ 'sstable_size_in_mb',
94
+ 'fanout_size'
95
+ )
96
+
97
+ date_tiered_compaction_strategy_options = (
98
+ 'base_time_seconds',
99
+ 'max_sstable_age_days',
100
+ 'min_threshold',
101
+ 'max_window_size_seconds',
102
+ 'timestamp_resolution'
103
+ )
104
+
105
+ time_window_compaction_strategy_options = (
106
+ 'compaction_window_unit',
107
+ 'compaction_window_size',
108
+ 'min_threshold',
109
+ 'timestamp_resolution'
110
+ )
111
+
112
+ @classmethod
113
+ def escape_value(cls, value):
114
+ if value is None:
115
+ return 'NULL' # this totally won't work
116
+ if isinstance(value, bool):
117
+ value = str(value).lower()
118
+ elif isinstance(value, float):
119
+ return '%f' % value
120
+ elif isinstance(value, int):
121
+ return str(value)
122
+ return "'%s'" % value.replace("'", "''")
123
+
124
+ @classmethod
125
+ def escape_name(cls, name):
126
+ if name is None:
127
+ return 'NULL'
128
+ return "'%s'" % name.replace("'", "''")
129
+
130
+ @staticmethod
131
+ def dequote_name(name):
132
+ name = name.strip()
133
+ if name == '':
134
+ return name
135
+ if name[0] == '"' and name[-1] == '"':
136
+ return name[1:-1].replace('""', '"')
137
+ else:
138
+ return name.lower()
139
+
140
+ @staticmethod
141
+ def dequote_value(cqlword):
142
+ cqlword = cqlword.strip()
143
+ if cqlword == '':
144
+ return cqlword
145
+ if cqlword[0] == "'" and cqlword[-1] == "'":
146
+ cqlword = cqlword[1:-1].replace("''", "'")
147
+ return cqlword
148
+
149
+
150
+ CqlRuleSet = Cql3ParsingRuleSet()
151
+
152
+ # convenience for remainder of module
153
+ completer_for = CqlRuleSet.completer_for
154
+ explain_completion = CqlRuleSet.explain_completion
155
+ dequote_value = CqlRuleSet.dequote_value
156
+ dequote_name = CqlRuleSet.dequote_name
157
+ escape_value = CqlRuleSet.escape_value
158
+
159
+ # BEGIN SYNTAX/COMPLETION RULE DEFINITIONS
160
+
161
+ syntax_rules = r'''
162
+ <Start> ::= <CQL_Statement>*
163
+ ;
164
+
165
+ <CQL_Statement> ::= [statements]=<statementBody> ";"
166
+ ;
167
+
168
+ # the order of these terminal productions is significant:
169
+ <endline> ::= /\n/ ;
170
+
171
+ JUNK ::= /([ \t\r\f\v]+|(--|[/][/])[^\n\r]*([\n\r]|$)|[/][*].*?[*][/])/ ;
172
+
173
+ <stringLiteral> ::= <quotedStringLiteral>
174
+ | <pgStringLiteral> ;
175
+ <quotedStringLiteral> ::= /'([^']|'')*'/ ;
176
+ <pgStringLiteral> ::= /\$\$(?:(?!\$\$).)*\$\$/;
177
+ <quotedName> ::= /"([^"]|"")*"/ ;
178
+ <float> ::= /-?[0-9]+\.[0-9]+/ ;
179
+ <uuid> ::= /[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/ ;
180
+ <blobLiteral> ::= /0x[0-9a-f]+/ ;
181
+ <wholenumber> ::= /[0-9]+/ ;
182
+ <identifier> ::= /[a-z][a-z0-9_]*/ ;
183
+ <colon> ::= ":" ;
184
+ <star> ::= "*" ;
185
+ <endtoken> ::= ";" ;
186
+ <op> ::= /[-+=%/,().]/ ;
187
+ <cmp> ::= /[<>!]=?/ ;
188
+ <brackets> ::= /[][{}]/ ;
189
+
190
+ <integer> ::= "-"? <wholenumber> ;
191
+ <boolean> ::= "true"
192
+ | "false"
193
+ ;
194
+
195
+ <unclosedPgString>::= /\$\$(?:(?!\$\$).)*/ ;
196
+ <unclosedString> ::= /'([^']|'')*/ ;
197
+ <unclosedName> ::= /"([^"]|"")*/ ;
198
+ <unclosedComment> ::= /[/][*].*$/ ;
199
+
200
+ <term> ::= <stringLiteral>
201
+ | <integer>
202
+ | <float>
203
+ | <uuid>
204
+ | <boolean>
205
+ | <blobLiteral>
206
+ | <collectionLiteral>
207
+ | <functionLiteral> <functionArguments>
208
+ | "NULL"
209
+ ;
210
+
211
+ <functionLiteral> ::= (<identifier> ( "." <identifier> )?)
212
+ | "TOKEN"
213
+ ;
214
+
215
+ <functionArguments> ::= "(" ( <term> ( "," <term> )* )? ")"
216
+ ;
217
+
218
+ <tokenDefinition> ::= token="TOKEN" "(" <term> ( "," <term> )* ")"
219
+ | <term>
220
+ ;
221
+ <cident> ::= <quotedName>
222
+ | <identifier>
223
+ | <unreservedKeyword>
224
+ ;
225
+ <colname> ::= <cident> ; # just an alias
226
+
227
+ <collectionLiteral> ::= <listLiteral>
228
+ | <setLiteral>
229
+ | <mapLiteral>
230
+ ;
231
+ <listLiteral> ::= "[" ( <term> ( "," <term> )* )? "]"
232
+ ;
233
+ <setLiteral> ::= "{" ( <term> ( "," <term> )* )? "}"
234
+ ;
235
+ <mapLiteral> ::= "{" <term> ":" <term> ( "," <term> ":" <term> )* "}"
236
+ ;
237
+
238
+ <anyFunctionName> ::= ( ksname=<cfOrKsName> dot="." )? udfname=<cfOrKsName> ;
239
+
240
+ <userFunctionName> ::= ( ksname=<nonSystemKeyspaceName> dot="." )? udfname=<cfOrKsName> ;
241
+
242
+ <refUserFunctionName> ::= udfname=<cfOrKsName> ;
243
+
244
+ <userAggregateName> ::= ( ksname=<nonSystemKeyspaceName> dot="." )? udaname=<cfOrKsName> ;
245
+
246
+ <functionAggregateName> ::= ( ksname=<nonSystemKeyspaceName> dot="." )? functionname=<cfOrKsName> ;
247
+
248
+ <aggregateName> ::= <userAggregateName>
249
+ ;
250
+
251
+ <functionName> ::= <functionAggregateName>
252
+ | "TOKEN"
253
+ ;
254
+
255
+ <statementBody> ::= <useStatement>
256
+ | <selectStatement>
257
+ | <dataChangeStatement>
258
+ | <schemaChangeStatement>
259
+ | <authenticationStatement>
260
+ | <authorizationStatement>
261
+ ;
262
+
263
+ <dataChangeStatement> ::= <insertStatement>
264
+ | <updateStatement>
265
+ | <deleteStatement>
266
+ | <truncateStatement>
267
+ | <batchStatement>
268
+ ;
269
+
270
+ <schemaChangeStatement> ::= <createKeyspaceStatement>
271
+ | <createColumnFamilyStatement>
272
+ | <createIndexStatement>
273
+ | <createMaterializedViewStatement>
274
+ | <createUserTypeStatement>
275
+ | <createFunctionStatement>
276
+ | <createAggregateStatement>
277
+ | <createTriggerStatement>
278
+ | <dropKeyspaceStatement>
279
+ | <dropColumnFamilyStatement>
280
+ | <dropIndexStatement>
281
+ | <dropMaterializedViewStatement>
282
+ | <dropUserTypeStatement>
283
+ | <dropFunctionStatement>
284
+ | <dropAggregateStatement>
285
+ | <dropTriggerStatement>
286
+ | <alterTableStatement>
287
+ | <alterKeyspaceStatement>
288
+ | <alterUserTypeStatement>
289
+ ;
290
+
291
+ <authenticationStatement> ::= <createUserStatement>
292
+ | <alterUserStatement>
293
+ | <dropUserStatement>
294
+ | <listUsersStatement>
295
+ | <createRoleStatement>
296
+ | <alterRoleStatement>
297
+ | <dropRoleStatement>
298
+ | <listRolesStatement>
299
+ | <createSlaStatement>
300
+ | <alterSlaStatement>
301
+ | <dropSlaStatement>
302
+ | <listSlaStatement>
303
+ | <attachSlaStatement>
304
+ | <detachRSlaStatement>
305
+ ;
306
+
307
+ <authorizationStatement> ::= <grantStatement>
308
+ | <grantRoleStatement>
309
+ | <revokeStatement>
310
+ | <revokeRoleStatement>
311
+ | <listPermissionsStatement>
312
+ ;
313
+
314
+ # timestamp is included here, since it's also a keyword
315
+ <simpleStorageType> ::= typename=( <identifier> | <stringLiteral> | "timestamp" ) ;
316
+
317
+ <userType> ::= utname=<cfOrKsName> ;
318
+
319
+ <storageType> ::= <simpleStorageType> | <collectionType> | <frozenCollectionType> | <userType> ;
320
+
321
+ # Note: autocomplete for frozen collection types does not handle nesting past depth 1 properly,
322
+ # but that's a lot of work to fix for little benefit.
323
+ <collectionType> ::= "map" "<" <simpleStorageType> "," ( <simpleStorageType> | <userType> ) ">"
324
+ | "list" "<" ( <simpleStorageType> | <userType> ) ">"
325
+ | "set" "<" ( <simpleStorageType> | <userType> ) ">"
326
+ ;
327
+
328
+ <frozenCollectionType> ::= "frozen" "<" "map" "<" <storageType> "," <storageType> ">" ">"
329
+ | "frozen" "<" "list" "<" <storageType> ">" ">"
330
+ | "frozen" "<" "set" "<" <storageType> ">" ">"
331
+ ;
332
+
333
+ <columnFamilyName> ::= ( ksname=<cfOrKsName> dot="." )? cfname=<cfOrKsName> ;
334
+
335
+ <materializedViewName> ::= ( ksname=<cfOrKsName> dot="." )? mvname=<cfOrKsName> ;
336
+
337
+ <userTypeName> ::= ( ksname=<cfOrKsName> dot="." )? utname=<cfOrKsName> ;
338
+
339
+ <keyspaceName> ::= ksname=<cfOrKsName> ;
340
+
341
+ <nonSystemKeyspaceName> ::= ksname=<cfOrKsName> ;
342
+
343
+ <alterableKeyspaceName> ::= ksname=<cfOrKsName> ;
344
+
345
+ <cfOrKsName> ::= <identifier>
346
+ | <quotedName>
347
+ | <unreservedKeyword>;
348
+
349
+ <unreservedKeyword> ::= nocomplete=
350
+ ( "key"
351
+ | "clustering"
352
+ # | "count" -- to get count(*) completion, treat count as reserved
353
+ | "ttl"
354
+ | "compact"
355
+ | "storage"
356
+ | "type"
357
+ | "values" )
358
+ ;
359
+
360
+ <property> ::= [propname]=<cident> propeq="=" [propval]=<propertyValue>
361
+ ;
362
+ <propertyValue> ::= propsimpleval=( <stringLiteral>
363
+ | <identifier>
364
+ | <integer>
365
+ | <float>
366
+ | <unreservedKeyword> )
367
+ # we don't use <mapLiteral> here so we can get more targeted
368
+ # completions:
369
+ | propsimpleval="{" [propmapkey]=<term> ":" [propmapval]=<term>
370
+ ( ender="," [propmapkey]=<term> ":" [propmapval]=<term> )*
371
+ ender="}"
372
+ ;
373
+
374
+ '''
375
+
376
+
377
+ def prop_equals_completer(ctxt, cass):
378
+ if not working_on_keyspace(ctxt):
379
+ # we know if the thing in the property name position is "compact" or
380
+ # "clustering" that there won't actually be an equals sign, because
381
+ # there are no properties by those names. there are, on the other hand,
382
+ # table properties that start with those keywords which don't have
383
+ # equals signs at all.
384
+ curprop = ctxt.get_binding('propname')[-1].upper()
385
+ if curprop in ('COMPACT', 'CLUSTERING'):
386
+ return ()
387
+ return ['=']
388
+
389
+
390
+ completer_for('property', 'propeq')(prop_equals_completer)
391
+
392
+
393
+ @completer_for('property', 'propname')
394
+ def prop_name_completer(ctxt, cass):
395
+ if working_on_keyspace(ctxt):
396
+ return ks_prop_name_completer(ctxt, cass)
397
+ else:
398
+ return cf_prop_name_completer(ctxt, cass)
399
+
400
+
401
+ @completer_for('propertyValue', 'propsimpleval')
402
+ def prop_val_completer(ctxt, cass):
403
+ if working_on_keyspace(ctxt):
404
+ return ks_prop_val_completer(ctxt, cass)
405
+ else:
406
+ return cf_prop_val_completer(ctxt, cass)
407
+
408
+
409
+ @completer_for('propertyValue', 'propmapkey')
410
+ def prop_val_mapkey_completer(ctxt, cass):
411
+ if working_on_keyspace(ctxt):
412
+ return ks_prop_val_mapkey_completer(ctxt, cass)
413
+ else:
414
+ return cf_prop_val_mapkey_completer(ctxt, cass)
415
+
416
+
417
+ @completer_for('propertyValue', 'propmapval')
418
+ def prop_val_mapval_completer(ctxt, cass):
419
+ if working_on_keyspace(ctxt):
420
+ return ks_prop_val_mapval_completer(ctxt, cass)
421
+ else:
422
+ return cf_prop_val_mapval_completer(ctxt, cass)
423
+
424
+
425
+ @completer_for('propertyValue', 'ender')
426
+ def prop_val_mapender_completer(ctxt, cass):
427
+ if working_on_keyspace(ctxt):
428
+ return ks_prop_val_mapender_completer(ctxt, cass)
429
+ else:
430
+ return cf_prop_val_mapender_completer(ctxt, cass)
431
+
432
+
433
+ def ks_prop_name_completer(ctxt, cass):
434
+ optsseen = ctxt.get_binding('propname', ())
435
+ if 'replication' not in optsseen:
436
+ return ['replication']
437
+ return ["durable_writes"]
438
+
439
+
440
+ def ks_prop_val_completer(ctxt, cass):
441
+ optname = ctxt.get_binding('propname')[-1]
442
+ if optname == 'durable_writes':
443
+ return ["'true'", "'false'"]
444
+ if optname == 'replication':
445
+ return ["{'class': 'NetworkTopologyStrategy'"]
446
+ return ()
447
+
448
+
449
+ def ks_prop_val_mapkey_completer(ctxt, cass):
450
+ optname = ctxt.get_binding('propname')[-1]
451
+ if optname != 'replication':
452
+ return ()
453
+ keysseen = list(map(dequote_value, ctxt.get_binding('propmapkey', ())))
454
+ valsseen = list(map(dequote_value, ctxt.get_binding('propmapval', ())))
455
+ for k, v in zip(keysseen, valsseen):
456
+ if k == 'class':
457
+ repclass = v
458
+ break
459
+ else:
460
+ return ["'class'"]
461
+ if repclass == 'SimpleStrategy':
462
+ opts = {'replication_factor'}
463
+ elif repclass == 'NetworkTopologyStrategy':
464
+ return [Hint('<dc_name>')]
465
+ return list(map(escape_value, opts.difference(keysseen)))
466
+
467
+
468
+ def ks_prop_val_mapval_completer(ctxt, cass):
469
+ optname = ctxt.get_binding('propname')[-1]
470
+ if optname != 'replication':
471
+ return ()
472
+ currentkey = dequote_value(ctxt.get_binding('propmapkey')[-1])
473
+ if currentkey == 'class':
474
+ partial = ctxt.get_binding('partial', '')
475
+ if partial == '':
476
+ return [escape_value('NetworkTopologyStrategy')]
477
+ return [s for s in CqlRuleSet.replication_strategies if s.startswith(partial)]
478
+ return [Hint('<term>')]
479
+
480
+
481
+ def ks_prop_val_mapender_completer(ctxt, cass):
482
+ optname = ctxt.get_binding('propname')[-1]
483
+ if optname != 'replication':
484
+ return [',']
485
+ keysseen = list(map(dequote_value, ctxt.get_binding('propmapkey', ())))
486
+ valsseen = list(map(dequote_value, ctxt.get_binding('propmapval', ())))
487
+ for k, v in zip(keysseen, valsseen):
488
+ if k == 'class':
489
+ repclass = v
490
+ break
491
+ else:
492
+ return [',']
493
+ if repclass == 'SimpleStrategy':
494
+ if 'replication_factor' not in keysseen:
495
+ return [',']
496
+ if repclass == 'NetworkTopologyStrategy' and len(keysseen) == 1:
497
+ return [',']
498
+ return ['}']
499
+
500
+
501
+ def cf_prop_name_completer(ctxt, cass):
502
+ return [c[0] for c in (CqlRuleSet.columnfamily_layout_options
503
+ + CqlRuleSet.columnfamily_layout_map_options)]
504
+
505
+
506
+ def cf_prop_val_completer(ctxt, cass):
507
+ exist_opts = ctxt.get_binding('propname')
508
+ this_opt = exist_opts[-1]
509
+ if this_opt == 'compression':
510
+ return ["{'sstable_compression': '"]
511
+ if this_opt == 'compaction':
512
+ return ["{'class': '"]
513
+ if this_opt == 'caching':
514
+ return ["{'keys': '"]
515
+ if any(this_opt == opt[0] for opt in CqlRuleSet.obsolete_cf_options):
516
+ return ["'<obsolete_option>'"]
517
+ if this_opt == 'bloom_filter_fp_chance':
518
+ return [Hint('<float_between_0_and_1>')]
519
+ if this_opt in ('min_compaction_threshold', 'max_compaction_threshold',
520
+ 'gc_grace_seconds', 'min_index_interval', 'max_index_interval'):
521
+ return [Hint('<integer>')]
522
+ if this_opt in ('cdc'):
523
+ return [Hint('<true|false>')]
524
+ if this_opt in ('read_repair'):
525
+ return [Hint('<\'none\'|\'blocking\'>')]
526
+ return [Hint('<option_value>')]
527
+
528
+
529
+ def cf_prop_val_mapkey_completer(ctxt, cass):
530
+ optname = ctxt.get_binding('propname')[-1]
531
+ for cql3option, _, subopts in CqlRuleSet.columnfamily_layout_map_options:
532
+ if optname == cql3option:
533
+ break
534
+ else:
535
+ return ()
536
+ keysseen = list(map(dequote_value, ctxt.get_binding('propmapkey', ())))
537
+ valsseen = list(map(dequote_value, ctxt.get_binding('propmapval', ())))
538
+ pairsseen = dict(list(zip(keysseen, valsseen)))
539
+ if optname == 'compression':
540
+ return list(map(escape_value, set(subopts).difference(keysseen)))
541
+ if optname == 'caching':
542
+ return list(map(escape_value, set(subopts).difference(keysseen)))
543
+ if optname == 'compaction':
544
+ opts = set(subopts)
545
+ try:
546
+ csc = pairsseen['class']
547
+ except KeyError:
548
+ return ["'class'"]
549
+ csc = csc.split('.')[-1]
550
+ if csc == 'SizeTieredCompactionStrategy':
551
+ opts = opts.union(set(CqlRuleSet.size_tiered_compaction_strategy_options))
552
+ elif csc == 'LeveledCompactionStrategy':
553
+ opts = opts.union(set(CqlRuleSet.leveled_compaction_strategy_options))
554
+ elif csc == 'DateTieredCompactionStrategy':
555
+ opts = opts.union(set(CqlRuleSet.date_tiered_compaction_strategy_options))
556
+ elif csc == 'TimeWindowCompactionStrategy':
557
+ opts = opts.union(set(CqlRuleSet.time_window_compaction_strategy_options))
558
+
559
+ return list(map(escape_value, opts))
560
+ return ()
561
+
562
+
563
+ def cf_prop_val_mapval_completer(ctxt, cass):
564
+ opt = ctxt.get_binding('propname')[-1]
565
+ key = dequote_value(ctxt.get_binding('propmapkey')[-1])
566
+ if opt == 'compaction':
567
+ if key == 'class':
568
+ return list(map(escape_value, CqlRuleSet.available_compaction_classes))
569
+ if key == 'provide_overlapping_tombstones':
570
+ return [Hint('<NONE|ROW|CELL>')]
571
+ return [Hint('<option_value>')]
572
+ elif opt == 'compression':
573
+ if key == 'sstable_compression':
574
+ return list(map(escape_value, CqlRuleSet.available_compression_classes))
575
+ return [Hint('<option_value>')]
576
+ elif opt == 'caching':
577
+ if key == 'rows_per_partition':
578
+ return ["'ALL'", "'NONE'", Hint('#rows_per_partition')]
579
+ elif key == 'keys':
580
+ return ["'ALL'", "'NONE'"]
581
+ return ()
582
+
583
+
584
+ def cf_prop_val_mapender_completer(ctxt, cass):
585
+ return [',', '}']
586
+
587
+
588
+ @completer_for('tokenDefinition', 'token')
589
+ def token_word_completer(ctxt, cass):
590
+ return ['token(']
591
+
592
+
593
+ @completer_for('simpleStorageType', 'typename')
594
+ def storagetype_completer(ctxt, cass):
595
+ return simple_cql_types
596
+
597
+
598
+ @completer_for('keyspaceName', 'ksname')
599
+ def ks_name_completer(ctxt, cass):
600
+ return list(map(maybe_escape_name, cass.get_keyspace_names()))
601
+
602
+
603
+ @completer_for('nonSystemKeyspaceName', 'ksname')
604
+ def non_system_ks_name_completer(ctxt, cass):
605
+ ksnames = [n for n in cass.get_keyspace_names() if n not in SYSTEM_KEYSPACES]
606
+ return list(map(maybe_escape_name, ksnames))
607
+
608
+
609
+ @completer_for('alterableKeyspaceName', 'ksname')
610
+ def alterable_ks_name_completer(ctxt, cass):
611
+ ksnames = [n for n in cass.get_keyspace_names() if n not in NONALTERBALE_KEYSPACES]
612
+ return list(map(maybe_escape_name, ksnames))
613
+
614
+
615
+ def cf_ks_name_completer(ctxt, cass):
616
+ return [maybe_escape_name(ks) + '.' for ks in cass.get_keyspace_names()]
617
+
618
+
619
+ completer_for('columnFamilyName', 'ksname')(cf_ks_name_completer)
620
+ completer_for('materializedViewName', 'ksname')(cf_ks_name_completer)
621
+
622
+
623
+ def cf_ks_dot_completer(ctxt, cass):
624
+ name = dequote_name(ctxt.get_binding('ksname'))
625
+ if name in cass.get_keyspace_names():
626
+ return ['.']
627
+ return []
628
+
629
+
630
+ completer_for('columnFamilyName', 'dot')(cf_ks_dot_completer)
631
+ completer_for('materializedViewName', 'dot')(cf_ks_dot_completer)
632
+
633
+
634
+ @completer_for('columnFamilyName', 'cfname')
635
+ def cf_name_completer(ctxt, cass):
636
+ ks = ctxt.get_binding('ksname', None)
637
+ if ks is not None:
638
+ ks = dequote_name(ks)
639
+ try:
640
+ cfnames = cass.get_columnfamily_names(ks)
641
+ except Exception:
642
+ if ks is None:
643
+ return ()
644
+ raise
645
+ return list(map(maybe_escape_name, cfnames))
646
+
647
+
648
+ @completer_for('materializedViewName', 'mvname')
649
+ def mv_name_completer(ctxt, cass):
650
+ ks = ctxt.get_binding('ksname', None)
651
+ if ks is not None:
652
+ ks = dequote_name(ks)
653
+ try:
654
+ mvnames = cass.get_materialized_view_names(ks)
655
+ except Exception:
656
+ if ks is None:
657
+ return ()
658
+ raise
659
+ return list(map(maybe_escape_name, mvnames))
660
+
661
+
662
+ completer_for('userTypeName', 'ksname')(cf_ks_name_completer)
663
+
664
+ completer_for('userTypeName', 'dot')(cf_ks_dot_completer)
665
+
666
+
667
+ def ut_name_completer(ctxt, cass):
668
+ ks = ctxt.get_binding('ksname', None)
669
+ if ks is not None:
670
+ ks = dequote_name(ks)
671
+ try:
672
+ utnames = cass.get_usertype_names(ks)
673
+ except Exception:
674
+ if ks is None:
675
+ return ()
676
+ raise
677
+ return list(map(maybe_escape_name, utnames))
678
+
679
+
680
+ completer_for('userTypeName', 'utname')(ut_name_completer)
681
+ completer_for('userType', 'utname')(ut_name_completer)
682
+
683
+
684
+ @completer_for('unreservedKeyword', 'nocomplete')
685
+ def unreserved_keyword_completer(ctxt, cass):
686
+ # we never want to provide completions through this production;
687
+ # this is always just to allow use of some keywords as column
688
+ # names, CF names, property values, etc.
689
+ return ()
690
+
691
+
692
+ def get_table_meta(ctxt, cass):
693
+ ks = ctxt.get_binding('ksname', None)
694
+ if ks is not None:
695
+ ks = dequote_name(ks)
696
+ cf = dequote_name(ctxt.get_binding('cfname'))
697
+ return cass.get_table_meta(ks, cf)
698
+
699
+
700
+ def get_ut_layout(ctxt, cass):
701
+ ks = ctxt.get_binding('ksname', None)
702
+ if ks is not None:
703
+ ks = dequote_name(ks)
704
+ ut = dequote_name(ctxt.get_binding('utname'))
705
+ return cass.get_usertype_layout(ks, ut)
706
+
707
+
708
+ def working_on_keyspace(ctxt):
709
+ wat = ctxt.get_binding('wat').upper()
710
+ if wat in ('KEYSPACE', 'SCHEMA'):
711
+ return True
712
+ return False
713
+
714
+
715
+ syntax_rules += r'''
716
+ <useStatement> ::= "USE" <keyspaceName>
717
+ ;
718
+ <selectStatement> ::= "SELECT" ( "JSON" )? <selectClause>
719
+ "FROM" (cf=<columnFamilyName> | mv=<materializedViewName>)
720
+ ( "WHERE" <whereClause> )?
721
+ ( "GROUP" "BY" <groupByClause> ( "," <groupByClause> )* )?
722
+ ( "ORDER" "BY" <orderByClause> ( "," <orderByClause> )* )?
723
+ ( "PER" "PARTITION" "LIMIT" perPartitionLimit=<wholenumber> )?
724
+ ( "LIMIT" limit=<wholenumber> )?
725
+ ( "ALLOW" "FILTERING" )?
726
+ ;
727
+ <whereClause> ::= <relation> ( "AND" <relation> )*
728
+ ;
729
+ <relation> ::= [rel_lhs]=<cident> ( "[" <term> "]" )? ( "=" | "<" | ">" | "<=" | ">=" | "CONTAINS" ( "KEY" )? ) <term>
730
+ | token="TOKEN" "(" [rel_tokname]=<cident>
731
+ ( "," [rel_tokname]=<cident> )*
732
+ ")" ("=" | "<" | ">" | "<=" | ">=") <tokenDefinition>
733
+ | [rel_lhs]=<cident> "IN" "(" <term> ( "," <term> )* ")"
734
+ ;
735
+ <selectClause> ::= "DISTINCT"? <selector> ("AS" <cident>)? ("," <selector> ("AS" <cident>)?)*
736
+ | "*"
737
+ ;
738
+ <udtSubfieldSelection> ::= <identifier> "." <identifier>
739
+ ;
740
+ <selector> ::= [colname]=<cident> ( "[" ( <term> ( ".." <term> "]" )? | <term> ".." ) )?
741
+ | <udtSubfieldSelection>
742
+ | "WRITETIME" "(" [colname]=<cident> ")"
743
+ | "MAXWRITETIME" "(" [colname]=<cident> ")"
744
+ | "TTL" "(" [colname]=<cident> ")"
745
+ | "COUNT" "(" star=( "*" | "1" ) ")"
746
+ | "CAST" "(" <selector> "AS" <storageType> ")"
747
+ | <functionName> <selectionFunctionArguments>
748
+ | <term>
749
+ ;
750
+ <selectionFunctionArguments> ::= "(" ( <selector> ( "," <selector> )* )? ")"
751
+ ;
752
+ <orderByClause> ::= [ordercol]=<cident> ( "ASC" | "DESC" )?
753
+ ;
754
+ <groupByClause> ::= [groupcol]=<cident>
755
+ | <functionName><groupByFunctionArguments>
756
+ ;
757
+ <groupByFunctionArguments> ::= "(" ( <groupByFunctionArgument> ( "," <groupByFunctionArgument> )* )? ")"
758
+ ;
759
+ <groupByFunctionArgument> ::= [groupcol]=<cident>
760
+ | <term>
761
+ ;
762
+ '''
763
+
764
+
765
+ def udf_name_completer(ctxt, cass):
766
+ ks = ctxt.get_binding('ksname', None)
767
+ if ks is not None:
768
+ ks = dequote_name(ks)
769
+ try:
770
+ udfnames = cass.get_userfunction_names(ks)
771
+ except Exception:
772
+ if ks is None:
773
+ return ()
774
+ raise
775
+ return list(map(maybe_escape_name, udfnames))
776
+
777
+
778
+ def uda_name_completer(ctxt, cass):
779
+ ks = ctxt.get_binding('ksname', None)
780
+ if ks is not None:
781
+ ks = dequote_name(ks)
782
+ try:
783
+ udanames = cass.get_useraggregate_names(ks)
784
+ except Exception:
785
+ if ks is None:
786
+ return ()
787
+ raise
788
+ return list(map(maybe_escape_name, udanames))
789
+
790
+
791
+ def udf_uda_name_completer(ctxt, cass):
792
+ ks = ctxt.get_binding('ksname', None)
793
+ if ks is not None:
794
+ ks = dequote_name(ks)
795
+ try:
796
+ functionnames = cass.get_userfunction_names(ks) + cass.get_useraggregate_names(ks)
797
+ except Exception:
798
+ if ks is None:
799
+ return ()
800
+ raise
801
+ return list(map(maybe_escape_name, functionnames))
802
+
803
+
804
+ def ref_udf_name_completer(ctxt, cass):
805
+ try:
806
+ udanames = cass.get_userfunction_names(None)
807
+ except Exception:
808
+ return ()
809
+ return list(map(maybe_escape_name, udanames))
810
+
811
+
812
+ completer_for('functionAggregateName', 'ksname')(cf_ks_name_completer)
813
+ completer_for('functionAggregateName', 'dot')(cf_ks_dot_completer)
814
+ completer_for('functionAggregateName', 'functionname')(udf_uda_name_completer)
815
+ completer_for('anyFunctionName', 'ksname')(cf_ks_name_completer)
816
+ completer_for('anyFunctionName', 'dot')(cf_ks_dot_completer)
817
+ completer_for('anyFunctionName', 'udfname')(udf_name_completer)
818
+ completer_for('userFunctionName', 'ksname')(cf_ks_name_completer)
819
+ completer_for('userFunctionName', 'dot')(cf_ks_dot_completer)
820
+ completer_for('userFunctionName', 'udfname')(udf_name_completer)
821
+ completer_for('refUserFunctionName', 'udfname')(ref_udf_name_completer)
822
+ completer_for('userAggregateName', 'ksname')(cf_ks_name_completer)
823
+ completer_for('userAggregateName', 'dot')(cf_ks_dot_completer)
824
+ completer_for('userAggregateName', 'udaname')(uda_name_completer)
825
+
826
+
827
+ @completer_for('orderByClause', 'ordercol')
828
+ def select_order_column_completer(ctxt, cass):
829
+ prev_order_cols = ctxt.get_binding('ordercol', ())
830
+ keyname = ctxt.get_binding('keyname')
831
+ if keyname is None:
832
+ keyname = ctxt.get_binding('rel_lhs', ())
833
+ if not keyname:
834
+ return [Hint("Can't ORDER BY here: need to specify partition key in WHERE clause")]
835
+ layout = get_table_meta(ctxt, cass)
836
+ order_by_candidates = [col.name for col in layout.clustering_key]
837
+ if len(order_by_candidates) > len(prev_order_cols):
838
+ return [maybe_escape_name(order_by_candidates[len(prev_order_cols)])]
839
+ return [Hint('No more orderable columns here.')]
840
+
841
+
842
+ @completer_for('groupByClause', 'groupcol')
843
+ def select_group_column_completer(ctxt, cass):
844
+ prev_group_cols = ctxt.get_binding('groupcol', ())
845
+ layout = get_table_meta(ctxt, cass)
846
+ group_by_candidates = [col.name for col in layout.primary_key]
847
+ if len(group_by_candidates) > len(prev_group_cols):
848
+ return [maybe_escape_name(group_by_candidates[len(prev_group_cols)])]
849
+ return [Hint('No more columns here.')]
850
+
851
+
852
+ @completer_for('relation', 'token')
853
+ def relation_token_word_completer(ctxt, cass):
854
+ return ['TOKEN(']
855
+
856
+
857
+ @completer_for('relation', 'rel_tokname')
858
+ def relation_token_subject_completer(ctxt, cass):
859
+ layout = get_table_meta(ctxt, cass)
860
+ return [key.name for key in layout.partition_key]
861
+
862
+
863
+ @completer_for('relation', 'rel_lhs')
864
+ def select_relation_lhs_completer(ctxt, cass):
865
+ layout = get_table_meta(ctxt, cass)
866
+ filterable = set()
867
+ already_filtered_on = list(map(dequote_name, ctxt.get_binding('rel_lhs', ())))
868
+ for num in range(0, len(layout.partition_key)):
869
+ if num == 0 or layout.partition_key[num - 1].name in already_filtered_on:
870
+ filterable.add(layout.partition_key[num].name)
871
+ else:
872
+ break
873
+ for num in range(0, len(layout.clustering_key)):
874
+ if num == 0 or layout.clustering_key[num - 1].name in already_filtered_on:
875
+ filterable.add(layout.clustering_key[num].name)
876
+ else:
877
+ break
878
+ for idx in layout.indexes.values():
879
+ filterable.add(idx.index_options["target"])
880
+ return list(map(maybe_escape_name, filterable))
881
+
882
+
883
+ explain_completion('selector', 'colname')
884
+
885
+ syntax_rules += r'''
886
+ <insertStatement> ::= "INSERT" "INTO" cf=<columnFamilyName>
887
+ ( ( "(" [colname]=<cident> ( "," [colname]=<cident> )* ")"
888
+ "VALUES" "(" [newval]=<term> ( valcomma="," [newval]=<term> )* valcomma=")")
889
+ | ("JSON" <stringLiteral>))
890
+ ( "IF" "NOT" "EXISTS")?
891
+ ( "USING" [insertopt]=<usingOption>
892
+ ( "AND" [insertopt]=<usingOption> )* )?
893
+ ;
894
+ <usingOption> ::= "TIMESTAMP" <wholenumber>
895
+ | "TTL" <wholenumber>
896
+ ;
897
+ '''
898
+
899
+
900
+ def regular_column_names(table_meta):
901
+ if not table_meta or not table_meta.columns:
902
+ return []
903
+ regular_columns = list(set(table_meta.columns.keys())
904
+ - set([key.name for key in table_meta.partition_key])
905
+ - set([key.name for key in table_meta.clustering_key]))
906
+ return regular_columns
907
+
908
+
909
+ @completer_for('insertStatement', 'colname')
910
+ def insert_colname_completer(ctxt, cass):
911
+ layout = get_table_meta(ctxt, cass)
912
+ colnames = set(map(dequote_name, ctxt.get_binding('colname', ())))
913
+ keycols = layout.primary_key
914
+ for k in keycols:
915
+ if k.name not in colnames:
916
+ return [maybe_escape_name(k.name)]
917
+ normalcols = set(regular_column_names(layout)) - colnames
918
+ return list(map(maybe_escape_name, normalcols))
919
+
920
+
921
+ @completer_for('insertStatement', 'newval')
922
+ def insert_newval_completer(ctxt, cass):
923
+ layout = get_table_meta(ctxt, cass)
924
+ insertcols = list(map(dequote_name, ctxt.get_binding('colname')))
925
+ valuesdone = ctxt.get_binding('newval', ())
926
+ if len(valuesdone) >= len(insertcols):
927
+ return []
928
+ curcol = insertcols[len(valuesdone)]
929
+ coltype = layout.columns[curcol].cql_type
930
+ if coltype in ('map', 'set'):
931
+ return ['{']
932
+ if coltype == 'list':
933
+ return ['[']
934
+ if coltype == 'boolean':
935
+ return ['true', 'false']
936
+
937
+ return [Hint('<value for %s (%s)>' % (maybe_escape_name(curcol),
938
+ coltype))]
939
+
940
+
941
+ @completer_for('insertStatement', 'valcomma')
942
+ def insert_valcomma_completer(ctxt, cass):
943
+ numcols = len(ctxt.get_binding('colname', ()))
944
+ numvals = len(ctxt.get_binding('newval', ()))
945
+ if numcols > numvals:
946
+ return [',']
947
+ return [')']
948
+
949
+
950
+ @completer_for('insertStatement', 'insertopt')
951
+ def insert_option_completer(ctxt, cass):
952
+ opts = set('TIMESTAMP TTL'.split())
953
+ for opt in ctxt.get_binding('insertopt', ()):
954
+ opts.discard(opt.split()[0])
955
+ return opts
956
+
957
+
958
+ syntax_rules += r'''
959
+ <updateStatement> ::= "UPDATE" cf=<columnFamilyName>
960
+ ( "USING" [updateopt]=<usingOption>
961
+ ( "AND" [updateopt]=<usingOption> )* )?
962
+ "SET" <assignment> ( "," <assignment> )*
963
+ "WHERE" <whereClause>
964
+ ( "IF" ( "EXISTS" | <conditions> ))?
965
+ ;
966
+ <assignment> ::= updatecol=<cident>
967
+ (( "=" update_rhs=( <term> | <cident> )
968
+ ( counterop=( "+" | "-" ) inc=<wholenumber>
969
+ | listadder="+" listcol=<cident> )? )
970
+ | ( indexbracket="[" <term> "]" "=" <term> )
971
+ | ( udt_field_dot="." udt_field=<identifier> "=" <term> ))
972
+ ;
973
+ <conditions> ::= <condition> ( "AND" <condition> )*
974
+ ;
975
+ <condition_op_and_rhs> ::= (("=" | "<" | ">" | "<=" | ">=" | "!=" | "CONTAINS" ( "KEY" )? ) <term>)
976
+ | ("IN" "(" <term> ( "," <term> )* ")" )
977
+ ;
978
+ <condition> ::= conditioncol=<cident>
979
+ ( (( indexbracket="[" <term> "]" )
980
+ |( udt_field_dot="." udt_field=<identifier> )) )?
981
+ <condition_op_and_rhs>
982
+ ;
983
+ '''
984
+
985
+
986
+ @completer_for('updateStatement', 'updateopt')
987
+ def update_option_completer(ctxt, cass):
988
+ opts = set('TIMESTAMP TTL'.split())
989
+ for opt in ctxt.get_binding('updateopt', ()):
990
+ opts.discard(opt.split()[0])
991
+ return opts
992
+
993
+
994
+ @completer_for('assignment', 'updatecol')
995
+ def update_col_completer(ctxt, cass):
996
+ layout = get_table_meta(ctxt, cass)
997
+ return list(map(maybe_escape_name, regular_column_names(layout)))
998
+
999
+
1000
+ @completer_for('assignment', 'update_rhs')
1001
+ def update_countername_completer(ctxt, cass):
1002
+ layout = get_table_meta(ctxt, cass)
1003
+ curcol = dequote_name(ctxt.get_binding('updatecol', ''))
1004
+ coltype = layout.columns[curcol].cql_type
1005
+ if coltype == 'counter':
1006
+ return [maybe_escape_name(curcol)]
1007
+ if coltype in ('map', 'set'):
1008
+ return ["{"]
1009
+ if coltype == 'list':
1010
+ return ["["]
1011
+ return [Hint('<term (%s)>' % coltype)]
1012
+
1013
+
1014
+ @completer_for('assignment', 'counterop')
1015
+ def update_counterop_completer(ctxt, cass):
1016
+ layout = get_table_meta(ctxt, cass)
1017
+ curcol = dequote_name(ctxt.get_binding('updatecol', ''))
1018
+ return ['+', '-'] if layout.columns[curcol].cql_type == 'counter' else []
1019
+
1020
+
1021
+ @completer_for('assignment', 'inc')
1022
+ def update_counter_inc_completer(ctxt, cass):
1023
+ layout = get_table_meta(ctxt, cass)
1024
+ curcol = dequote_name(ctxt.get_binding('updatecol', ''))
1025
+ if layout.columns[curcol].cql_type == 'counter':
1026
+ return [Hint('<wholenumber>')]
1027
+ return []
1028
+
1029
+
1030
+ @completer_for('assignment', 'listadder')
1031
+ def update_listadder_completer(ctxt, cass):
1032
+ rhs = ctxt.get_binding('update_rhs')
1033
+ if rhs.startswith('['):
1034
+ return ['+']
1035
+ return []
1036
+
1037
+
1038
+ @completer_for('assignment', 'listcol')
1039
+ def update_listcol_completer(ctxt, cass):
1040
+ rhs = ctxt.get_binding('update_rhs')
1041
+ if rhs.startswith('['):
1042
+ colname = dequote_name(ctxt.get_binding('updatecol'))
1043
+ return [maybe_escape_name(colname)]
1044
+ return []
1045
+
1046
+
1047
+ @completer_for('assignment', 'indexbracket')
1048
+ def update_indexbracket_completer(ctxt, cass):
1049
+ layout = get_table_meta(ctxt, cass)
1050
+ curcol = dequote_name(ctxt.get_binding('updatecol', ''))
1051
+ coltype = layout.columns[curcol].cql_type
1052
+ if coltype in ('map', 'list'):
1053
+ return ['[']
1054
+ return []
1055
+
1056
+
1057
+ @completer_for('assignment', 'udt_field_dot')
1058
+ def update_udt_field_dot_completer(ctxt, cass):
1059
+ layout = get_table_meta(ctxt, cass)
1060
+ curcol = dequote_name(ctxt.get_binding('updatecol', ''))
1061
+ return ["."] if _is_usertype(layout, curcol) else []
1062
+
1063
+
1064
+ @completer_for('assignment', 'udt_field')
1065
+ def assignment_udt_field_completer(ctxt, cass):
1066
+ layout = get_table_meta(ctxt, cass)
1067
+ curcol = dequote_name(ctxt.get_binding('updatecol', ''))
1068
+ return _usertype_fields(ctxt, cass, layout, curcol)
1069
+
1070
+
1071
+ def _is_usertype(layout, curcol):
1072
+ coltype = layout.columns[curcol].cql_type
1073
+ return coltype not in simple_cql_types and coltype not in ('map', 'set', 'list')
1074
+
1075
+
1076
+ def _usertype_fields(ctxt, cass, layout, curcol):
1077
+ if not _is_usertype(layout, curcol):
1078
+ return []
1079
+
1080
+ coltype = layout.columns[curcol].cql_type
1081
+ ks = ctxt.get_binding('ksname', None)
1082
+ if ks is not None:
1083
+ ks = dequote_name(ks)
1084
+ user_type = cass.get_usertype_layout(ks, coltype)
1085
+ return [field_name for (field_name, field_type) in user_type]
1086
+
1087
+
1088
+ @completer_for('condition', 'indexbracket')
1089
+ def condition_indexbracket_completer(ctxt, cass):
1090
+ layout = get_table_meta(ctxt, cass)
1091
+ curcol = dequote_name(ctxt.get_binding('conditioncol', ''))
1092
+ coltype = layout.columns[curcol].cql_type
1093
+ if coltype in ('map', 'list'):
1094
+ return ['[']
1095
+ return []
1096
+
1097
+
1098
+ @completer_for('condition', 'udt_field_dot')
1099
+ def condition_udt_field_dot_completer(ctxt, cass):
1100
+ layout = get_table_meta(ctxt, cass)
1101
+ curcol = dequote_name(ctxt.get_binding('conditioncol', ''))
1102
+ return ["."] if _is_usertype(layout, curcol) else []
1103
+
1104
+
1105
+ @completer_for('condition', 'udt_field')
1106
+ def condition_udt_field_completer(ctxt, cass):
1107
+ layout = get_table_meta(ctxt, cass)
1108
+ curcol = dequote_name(ctxt.get_binding('conditioncol', ''))
1109
+ return _usertype_fields(ctxt, cass, layout, curcol)
1110
+
1111
+
1112
+ syntax_rules += r'''
1113
+ <deleteStatement> ::= "DELETE" ( <deleteSelector> ( "," <deleteSelector> )* )?
1114
+ "FROM" cf=<columnFamilyName>
1115
+ ( "USING" [delopt]=<deleteOption> )?
1116
+ "WHERE" <whereClause>
1117
+ ( "IF" ( "EXISTS" | <conditions> ) )?
1118
+ ;
1119
+ <deleteSelector> ::= delcol=<cident>
1120
+ ( ( "[" <term> "]" )
1121
+ | ( "." <identifier> ) )?
1122
+ ;
1123
+ <deleteOption> ::= "TIMESTAMP" <wholenumber>
1124
+ ;
1125
+ '''
1126
+
1127
+
1128
+ @completer_for('deleteStatement', 'delopt')
1129
+ def delete_opt_completer(ctxt, cass):
1130
+ opts = set('TIMESTAMP'.split())
1131
+ for opt in ctxt.get_binding('delopt', ()):
1132
+ opts.discard(opt.split()[0])
1133
+ return opts
1134
+
1135
+
1136
+ @completer_for('deleteSelector', 'delcol')
1137
+ def delete_delcol_completer(ctxt, cass):
1138
+ layout = get_table_meta(ctxt, cass)
1139
+ return list(map(maybe_escape_name, regular_column_names(layout)))
1140
+
1141
+
1142
+ syntax_rules += r'''
1143
+ <batchStatement> ::= "BEGIN" ( "UNLOGGED" | "COUNTER" )? "BATCH"
1144
+ ( "USING" [batchopt]=<usingOption>
1145
+ ( "AND" [batchopt]=<usingOption> )* )?
1146
+ [batchstmt]=<batchStatementMember> ";"?
1147
+ ( [batchstmt]=<batchStatementMember> ";"? )*
1148
+ "APPLY" "BATCH"
1149
+ ;
1150
+ <batchStatementMember> ::= <insertStatement>
1151
+ | <updateStatement>
1152
+ | <deleteStatement>
1153
+ ;
1154
+ '''
1155
+
1156
+
1157
+ @completer_for('batchStatement', 'batchopt')
1158
+ def batch_opt_completer(ctxt, cass):
1159
+ opts = set('TIMESTAMP'.split())
1160
+ for opt in ctxt.get_binding('batchopt', ()):
1161
+ opts.discard(opt.split()[0])
1162
+ return opts
1163
+
1164
+
1165
+ syntax_rules += r'''
1166
+ <truncateStatement> ::= "TRUNCATE" ("COLUMNFAMILY" | "TABLE")? cf=<columnFamilyName>
1167
+ ;
1168
+ '''
1169
+
1170
+ syntax_rules += r'''
1171
+ <createKeyspaceStatement> ::= "CREATE" wat=( "KEYSPACE" | "SCHEMA" ) ("IF" "NOT" "EXISTS")? ksname=<cfOrKsName>
1172
+ "WITH" <property> ( "AND" <property> )*
1173
+ ;
1174
+ '''
1175
+
1176
+
1177
+ @completer_for('createKeyspaceStatement', 'wat')
1178
+ def create_ks_wat_completer(ctxt, cass):
1179
+ # would prefer to get rid of the "schema" nomenclature in cql3
1180
+ if ctxt.get_binding('partial', '') == '':
1181
+ return ['KEYSPACE']
1182
+ return ['KEYSPACE', 'SCHEMA']
1183
+
1184
+
1185
+ syntax_rules += r'''
1186
+ <createColumnFamilyStatement> ::= "CREATE" wat=( "COLUMNFAMILY" | "TABLE" ) ("IF" "NOT" "EXISTS")?
1187
+ ( ks=<nonSystemKeyspaceName> dot="." )? cf=<cfOrKsName>
1188
+ "(" ( <singleKeyCfSpec> | <compositeKeyCfSpec> ) ")"
1189
+ ( "WITH" <cfamProperty> ( "AND" <cfamProperty> )* )?
1190
+ ;
1191
+
1192
+ <cfamProperty> ::= <property>
1193
+ | "COMPACT" "STORAGE" "CDC"
1194
+ | "CLUSTERING" "ORDER" "BY" "(" <cfamOrdering>
1195
+ ( "," <cfamOrdering> )* ")"
1196
+ ;
1197
+
1198
+ <cfamOrdering> ::= [ordercol]=<cident> ( "ASC" | "DESC" )
1199
+ ;
1200
+
1201
+ <singleKeyCfSpec> ::= [newcolname]=<cident> <storageType> "PRIMARY" "KEY"
1202
+ ( "," [newcolname]=<cident> <storageType> )*
1203
+ ;
1204
+
1205
+ <compositeKeyCfSpec> ::= [newcolname]=<cident> <storageType>
1206
+ "," [newcolname]=<cident> <storageType> ( "static" )?
1207
+ ( "," [newcolname]=<cident> <storageType> ( "static" )? )*
1208
+ "," "PRIMARY" k="KEY" p="(" ( partkey=<pkDef> | [pkey]=<cident> )
1209
+ ( c="," [pkey]=<cident> )* ")"
1210
+ ;
1211
+
1212
+ <pkDef> ::= "(" [ptkey]=<cident> "," [ptkey]=<cident>
1213
+ ( "," [ptkey]=<cident> )* ")"
1214
+ ;
1215
+ '''
1216
+
1217
+
1218
+ @completer_for('cfamOrdering', 'ordercol')
1219
+ def create_cf_clustering_order_colname_completer(ctxt, cass):
1220
+ colnames = list(map(dequote_name, ctxt.get_binding('newcolname', ())))
1221
+ # Definitely some of these aren't valid for ordering, but I'm not sure
1222
+ # precisely which are. This is good enough for now
1223
+ return colnames
1224
+
1225
+
1226
+ @completer_for('createColumnFamilyStatement', 'wat')
1227
+ def create_cf_wat_completer(ctxt, cass):
1228
+ # would prefer to get rid of the "columnfamily" nomenclature in cql3
1229
+ if ctxt.get_binding('partial', '') == '':
1230
+ return ['TABLE']
1231
+ return ['TABLE', 'COLUMNFAMILY']
1232
+
1233
+
1234
+ explain_completion('createColumnFamilyStatement', 'cf', '<new_table_name>')
1235
+ explain_completion('compositeKeyCfSpec', 'newcolname', '<new_column_name>')
1236
+
1237
+
1238
+ @completer_for('createColumnFamilyStatement', 'dot')
1239
+ def create_cf_ks_dot_completer(ctxt, cass):
1240
+ ks = dequote_name(ctxt.get_binding('ks'))
1241
+ if ks in cass.get_keyspace_names():
1242
+ return ['.']
1243
+ return []
1244
+
1245
+
1246
+ @completer_for('pkDef', 'ptkey')
1247
+ def create_cf_pkdef_declaration_completer(ctxt, cass):
1248
+ cols_declared = ctxt.get_binding('newcolname')
1249
+ pieces_already = ctxt.get_binding('ptkey', ())
1250
+ pieces_already = list(map(dequote_name, pieces_already))
1251
+ while cols_declared[0] in pieces_already:
1252
+ cols_declared = cols_declared[1:]
1253
+ if len(cols_declared) < 2:
1254
+ return ()
1255
+ return [maybe_escape_name(cols_declared[0])]
1256
+
1257
+
1258
+ @completer_for('compositeKeyCfSpec', 'pkey')
1259
+ def create_cf_composite_key_declaration_completer(ctxt, cass):
1260
+ cols_declared = ctxt.get_binding('newcolname')
1261
+ pieces_already = ctxt.get_binding('ptkey', ()) + ctxt.get_binding('pkey', ())
1262
+ pieces_already = list(map(dequote_name, pieces_already))
1263
+ while cols_declared[0] in pieces_already:
1264
+ cols_declared = cols_declared[1:]
1265
+ if len(cols_declared) < 2:
1266
+ return ()
1267
+ return [maybe_escape_name(cols_declared[0])]
1268
+
1269
+
1270
+ @completer_for('compositeKeyCfSpec', 'k')
1271
+ def create_cf_composite_primary_key_keyword_completer(ctxt, cass):
1272
+ return ['KEY (']
1273
+
1274
+
1275
+ @completer_for('compositeKeyCfSpec', 'p')
1276
+ def create_cf_composite_primary_key_paren_completer(ctxt, cass):
1277
+ return ['(']
1278
+
1279
+
1280
+ @completer_for('compositeKeyCfSpec', 'c')
1281
+ def create_cf_composite_primary_key_comma_completer(ctxt, cass):
1282
+ cols_declared = ctxt.get_binding('newcolname')
1283
+ pieces_already = ctxt.get_binding('pkey', ())
1284
+ if len(pieces_already) >= len(cols_declared) - 1:
1285
+ return ()
1286
+ return [',']
1287
+
1288
+
1289
+ syntax_rules += r'''
1290
+
1291
+ <idxName> ::= <identifier>
1292
+ | <quotedName>
1293
+ | <unreservedKeyword>;
1294
+
1295
+ <createIndexStatement> ::= "CREATE" "CUSTOM"? "INDEX" ("IF" "NOT" "EXISTS")? indexname=<idxName>? "ON"
1296
+ cf=<columnFamilyName> "(" (
1297
+ col=<cident> |
1298
+ "keys(" col=<cident> ")" |
1299
+ "full(" col=<cident> ")"
1300
+ ) ")"
1301
+ ( "USING" <stringLiteral> ( "WITH" "OPTIONS" "=" <mapLiteral> )? )?
1302
+ ;
1303
+
1304
+ <createMaterializedViewStatement> ::= "CREATE" "MATERIALIZED" "VIEW" ("IF" "NOT" "EXISTS")? <materializedViewName>?
1305
+ "AS" <selectStatement>
1306
+ "PRIMARY" "KEY" <pkDef>
1307
+ ;
1308
+
1309
+ <createUserTypeStatement> ::= "CREATE" "TYPE" ( ks=<nonSystemKeyspaceName> dot="." )? typename=<cfOrKsName> "(" newcol=<cident> <storageType>
1310
+ ( "," [newcolname]=<cident> <storageType> )*
1311
+ ")"
1312
+ ;
1313
+
1314
+ <createFunctionStatement> ::= "CREATE" ("OR" "REPLACE")? "FUNCTION"
1315
+ ("IF" "NOT" "EXISTS")?
1316
+ <userFunctionName>
1317
+ ( "(" ( newcol=<cident> <storageType>
1318
+ ( "," [newcolname]=<cident> <storageType> )* )?
1319
+ ")" )?
1320
+ ("RETURNS" "NULL" | "CALLED") "ON" "NULL" "INPUT"
1321
+ "RETURNS" <storageType>
1322
+ "LANGUAGE" <cident> "AS" <stringLiteral>
1323
+ ;
1324
+
1325
+ <createAggregateStatement> ::= "CREATE" ("OR" "REPLACE")? "AGGREGATE"
1326
+ ("IF" "NOT" "EXISTS")?
1327
+ <userAggregateName>
1328
+ ( "("
1329
+ ( <storageType> ( "," <storageType> )* )?
1330
+ ")" )?
1331
+ "SFUNC" <refUserFunctionName>
1332
+ "STYPE" <storageType>
1333
+ ( "FINALFUNC" <refUserFunctionName> )?
1334
+ ( "INITCOND" <term> )?
1335
+ ;
1336
+
1337
+ '''
1338
+
1339
+ explain_completion('createIndexStatement', 'indexname', '<new_index_name>')
1340
+ explain_completion('createUserTypeStatement', 'typename', '<new_type_name>')
1341
+ explain_completion('createUserTypeStatement', 'newcol', '<new_field_name>')
1342
+
1343
+
1344
+ @completer_for('createIndexStatement', 'col')
1345
+ def create_index_col_completer(ctxt, cass):
1346
+ """ Return the columns for which an index doesn't exist yet. """
1347
+ layout = get_table_meta(ctxt, cass)
1348
+ idx_targets = [idx.index_options["target"] for idx in layout.indexes.values()]
1349
+ colnames = [cd.name for cd in list(layout.columns.values()) if cd.name not in idx_targets]
1350
+ return list(map(maybe_escape_name, colnames))
1351
+
1352
+
1353
+ syntax_rules += r'''
1354
+ <dropKeyspaceStatement> ::= "DROP" "KEYSPACE" ("IF" "EXISTS")? ksname=<nonSystemKeyspaceName>
1355
+ ;
1356
+
1357
+ <dropColumnFamilyStatement> ::= "DROP" ( "COLUMNFAMILY" | "TABLE" ) ("IF" "EXISTS")? cf=<columnFamilyName>
1358
+ ;
1359
+
1360
+ <indexName> ::= ( ksname=<idxOrKsName> dot="." )? idxname=<idxOrKsName> ;
1361
+
1362
+ <idxOrKsName> ::= <identifier>
1363
+ | <quotedName>
1364
+ | <unreservedKeyword>;
1365
+
1366
+ <dropIndexStatement> ::= "DROP" "INDEX" ("IF" "EXISTS")? idx=<indexName>
1367
+ ;
1368
+
1369
+ <dropMaterializedViewStatement> ::= "DROP" "MATERIALIZED" "VIEW" ("IF" "EXISTS")? mv=<materializedViewName>
1370
+ ;
1371
+
1372
+ <dropUserTypeStatement> ::= "DROP" "TYPE" ut=<userTypeName>
1373
+ ;
1374
+
1375
+ <dropFunctionStatement> ::= "DROP" "FUNCTION" ( "IF" "EXISTS" )? <userFunctionName>
1376
+ ;
1377
+
1378
+ <dropAggregateStatement> ::= "DROP" "AGGREGATE" ( "IF" "EXISTS" )? <userAggregateName>
1379
+ ;
1380
+
1381
+ '''
1382
+
1383
+
1384
+ @completer_for('indexName', 'ksname')
1385
+ def idx_ks_name_completer(ctxt, cass):
1386
+ return [maybe_escape_name(ks) + '.' for ks in cass.get_keyspace_names()]
1387
+
1388
+
1389
+ @completer_for('indexName', 'dot')
1390
+ def idx_ks_dot_completer(ctxt, cass):
1391
+ name = dequote_name(ctxt.get_binding('ksname'))
1392
+ if name in cass.get_keyspace_names():
1393
+ return ['.']
1394
+ return []
1395
+
1396
+
1397
+ @completer_for('indexName', 'idxname')
1398
+ def idx_ks_idx_name_completer(ctxt, cass):
1399
+ ks = ctxt.get_binding('ksname', None)
1400
+ if ks is not None:
1401
+ ks = dequote_name(ks)
1402
+ try:
1403
+ idxnames = cass.get_index_names(ks)
1404
+ except Exception:
1405
+ if ks is None:
1406
+ return ()
1407
+ raise
1408
+ return list(map(maybe_escape_name, idxnames))
1409
+
1410
+
1411
+ syntax_rules += r'''
1412
+ <alterTableStatement> ::= "ALTER" wat=( "COLUMNFAMILY" | "TABLE" ) ("IF" "EXISTS")? cf=<columnFamilyName>
1413
+ <alterInstructions>
1414
+ ;
1415
+ <alterInstructions> ::= "ADD" ("IF" "NOT" "EXISTS")? newcol=<cident> <storageType> ("static")?
1416
+ | "DROP" ("IF" "EXISTS")? existcol=<cident>
1417
+ | "WITH" <cfamProperty> ( "AND" <cfamProperty> )*
1418
+ | "RENAME" ("IF" "EXISTS")? existcol=<cident> "TO" newcol=<cident>
1419
+ ( "AND" existcol=<cident> "TO" newcol=<cident> )*
1420
+ ;
1421
+
1422
+ <alterUserTypeStatement> ::= "ALTER" "TYPE" ("IF" "EXISTS")? ut=<userTypeName>
1423
+ <alterTypeInstructions>
1424
+ ;
1425
+ <alterTypeInstructions> ::= "ADD" ("IF" "NOT" "EXISTS")? newcol=<cident> <storageType>
1426
+ | "RENAME" ("IF" "EXISTS")? existcol=<cident> "TO" newcol=<cident>
1427
+ ( "AND" existcol=<cident> "TO" newcol=<cident> )*
1428
+ ;
1429
+ '''
1430
+
1431
+
1432
+ @completer_for('alterInstructions', 'existcol')
1433
+ def alter_table_col_completer(ctxt, cass):
1434
+ layout = get_table_meta(ctxt, cass)
1435
+ cols = [str(md) for md in layout.columns]
1436
+ return list(map(maybe_escape_name, cols))
1437
+
1438
+
1439
+ @completer_for('alterTypeInstructions', 'existcol')
1440
+ def alter_type_field_completer(ctxt, cass):
1441
+ layout = get_ut_layout(ctxt, cass)
1442
+ fields = [atuple[0] for atuple in layout]
1443
+ return list(map(maybe_escape_name, fields))
1444
+
1445
+
1446
+ explain_completion('alterInstructions', 'newcol', '<new_column_name>')
1447
+ explain_completion('alterTypeInstructions', 'newcol', '<new_field_name>')
1448
+
1449
+
1450
+ syntax_rules += r'''
1451
+ <alterKeyspaceStatement> ::= "ALTER" wat=( "KEYSPACE" | "SCHEMA" ) ("IF" "EXISTS")? ks=<alterableKeyspaceName>
1452
+ "WITH" <property> ( "AND" <property> )*
1453
+ ;
1454
+ '''
1455
+
1456
+ syntax_rules += r'''
1457
+ <username> ::= name=( <identifier> | <stringLiteral> )
1458
+ ;
1459
+
1460
+ <createUserStatement> ::= "CREATE" "USER" ( "IF" "NOT" "EXISTS" )? <username>
1461
+ ( "WITH" ("HASHED")? "PASSWORD" <stringLiteral> )?
1462
+ ( "SUPERUSER" | "NOSUPERUSER" )?
1463
+ ;
1464
+
1465
+ <alterUserStatement> ::= "ALTER" "USER" ("IF" "EXISTS")? <username>
1466
+ ( "WITH" "PASSWORD" <stringLiteral> )?
1467
+ ( "SUPERUSER" | "NOSUPERUSER" )?
1468
+ ;
1469
+
1470
+ <dropUserStatement> ::= "DROP" "USER" ( "IF" "EXISTS" )? <username>
1471
+ ;
1472
+
1473
+ <listUsersStatement> ::= "LIST" "USERS"
1474
+ ;
1475
+ '''
1476
+
1477
+ syntax_rules += r'''
1478
+ <rolename> ::= <identifier>
1479
+ | <quotedName>
1480
+ | <unreservedKeyword>
1481
+ ;
1482
+
1483
+ <createRoleStatement> ::= "CREATE" "ROLE" <rolename>
1484
+ ( "WITH" <roleProperty> ("AND" <roleProperty>)*)?
1485
+ ;
1486
+
1487
+ <alterRoleStatement> ::= "ALTER" "ROLE" ("IF" "EXISTS")? <rolename>
1488
+ ( "WITH" <roleProperty> ("AND" <roleProperty>)*)?
1489
+ ;
1490
+
1491
+ <roleProperty> ::= (("HASHED")? "PASSWORD") "=" <stringLiteral>
1492
+ | "OPTIONS" "=" <mapLiteral>
1493
+ | "SUPERUSER" "=" <boolean>
1494
+ | "LOGIN" "=" <boolean>
1495
+ | "ACCESS" "TO" "DATACENTERS" <setLiteral>
1496
+ | "ACCESS" "TO" "ALL" "DATACENTERS"
1497
+ ;
1498
+
1499
+ <dropRoleStatement> ::= "DROP" "ROLE" <rolename>
1500
+ ;
1501
+
1502
+ <grantRoleStatement> ::= "GRANT" <rolename> "TO" <rolename>
1503
+ ;
1504
+
1505
+ <revokeRoleStatement> ::= "REVOKE" <rolename> "FROM" <rolename>
1506
+ ;
1507
+
1508
+ <listRolesStatement> ::= "LIST" "ROLES"
1509
+ ( "OF" <rolename> )? "NORECURSIVE"?
1510
+ ;
1511
+ '''
1512
+
1513
+ syntax_rules += r'''
1514
+ <slaName> ::= <identifier>
1515
+ | <quotedName>
1516
+ | <unreservedKeyword>
1517
+ ;
1518
+
1519
+ <createSlaStatement> ::= "CREATE" "SERVICE_LEVEL" ( "IF" "NOT" "EXISTS" )? <slaName>
1520
+ ( "WITH" <slaProperty> ("AND" <slaProperty>)*)?
1521
+ ;
1522
+
1523
+ <alterSlaStatement> ::= "ALTER" "SERVICE_LEVEL" ("IF" "EXISTS")? <slaName>
1524
+ ( "WITH" <slaProperty> ("AND" <slaProperty>)*)?
1525
+ ;
1526
+
1527
+ <slaProperty> ::= "WORKLOAD_TYPE" "=" <stringLiteral>
1528
+ | "TIMEOUT" "=" <wholenumber>
1529
+ | "SHARES" "=" <wholenumber>
1530
+ ;
1531
+
1532
+ <dropSlaStatement> ::= "DROP" "SERVICE_LEVEL" ("IF" "EXISTS")? <slaName>
1533
+ ;
1534
+
1535
+ <listSlaStatement> ::= ("LIST" "SERVICE_LEVEL" <slaName> )
1536
+ | ("LIST" "ATTACHED" "SERVICE_LEVEL" "OF" <rolename> )
1537
+ | ("LIST" "ALL" "SERVICE_LEVELS" )
1538
+ | ("LIST" "ALL" "ATTACHED" "SERVICE_LEVELS" )
1539
+ ;
1540
+
1541
+ <attachSlaStatement> ::= "ATTACH" "SERVICE_LEVEL" <slaName> "TO" <rolename>
1542
+ ;
1543
+
1544
+ <detachRSlaStatement> ::= "DETACH" "SERVICE_LEVEL" <slaName> "FROM" <rolename>
1545
+ ;
1546
+ '''
1547
+
1548
+ syntax_rules += r'''
1549
+ <grantStatement> ::= "GRANT" <permissionExpr> "ON" <resource> "TO" <rolename>
1550
+ ;
1551
+
1552
+ <revokeStatement> ::= "REVOKE" <permissionExpr> "ON" <resource> "FROM" <rolename>
1553
+ ;
1554
+
1555
+ <listPermissionsStatement> ::= "LIST" <permissionExpr>
1556
+ ( "ON" <resource> )? ( "OF" <rolename> )? "NORECURSIVE"?
1557
+ ;
1558
+
1559
+ <permission> ::= "AUTHORIZE"
1560
+ | "CREATE"
1561
+ | "ALTER"
1562
+ | "DROP"
1563
+ | "SELECT"
1564
+ | "MODIFY"
1565
+ | "DESCRIBE"
1566
+ | "EXECUTE"
1567
+ ;
1568
+
1569
+ <permissionExpr> ::= ( [newpermission]=<permission> "PERMISSION"? ( "," [newpermission]=<permission> "PERMISSION"? )* )
1570
+ | ( "ALL" "PERMISSIONS"? )
1571
+ ;
1572
+
1573
+ <resource> ::= <dataResource>
1574
+ | <roleResource>
1575
+ | <functionResource>
1576
+ | <jmxResource>
1577
+ ;
1578
+
1579
+ <dataResource> ::= ( "ALL" "KEYSPACES" )
1580
+ | ( "KEYSPACE" <keyspaceName> )
1581
+ | ( "ALL" "TABLES" "IN" "KEYSPACE" <keyspaceName> )
1582
+ | ( "TABLE"? <columnFamilyName> )
1583
+ ;
1584
+
1585
+ <roleResource> ::= ("ALL" "ROLES")
1586
+ | ("ROLE" <rolename>)
1587
+ ;
1588
+
1589
+ <functionResource> ::= ( "ALL" "FUNCTIONS" ("IN KEYSPACE" <keyspaceName>)? )
1590
+ | ( "FUNCTION" <functionAggregateName>
1591
+ ( "(" ( newcol=<cident> <storageType>
1592
+ ( "," [newcolname]=<cident> <storageType> )* )?
1593
+ ")" )
1594
+ )
1595
+ ;
1596
+
1597
+ <jmxResource> ::= ( "ALL" "MBEANS")
1598
+ | ( ( "MBEAN" | "MBEANS" ) <stringLiteral> )
1599
+ ;
1600
+
1601
+ '''
1602
+
1603
+
1604
+ @completer_for('permissionExpr', 'newpermission')
1605
+ def permission_completer(ctxt, _):
1606
+ new_permissions = set([permission.upper() for permission in ctxt.get_binding('newpermission')])
1607
+ all_permissions = set([permission.arg for permission in ctxt.ruleset['permission'].arg])
1608
+ suggestions = all_permissions - new_permissions
1609
+ if len(suggestions) == 0:
1610
+ return [Hint('No more permissions here.')]
1611
+ return suggestions
1612
+
1613
+
1614
+ @completer_for('username', 'name')
1615
+ def username_name_completer(ctxt, cass):
1616
+ def maybe_quote(name):
1617
+ if CqlRuleSet.is_valid_cql3_name(name):
1618
+ return name
1619
+ return "'%s'" % name
1620
+
1621
+ # disable completion for CREATE USER.
1622
+ if ctxt.matched[0][1].upper() == 'CREATE':
1623
+ return [Hint('<username>')]
1624
+
1625
+ session = cass.session
1626
+ return [maybe_quote(list(row.values())[0].replace("'", "''")) for row in session.execute("LIST USERS")]
1627
+
1628
+
1629
+ @completer_for('rolename', 'role')
1630
+ def rolename_completer(ctxt, cass):
1631
+ def maybe_quote(name):
1632
+ if CqlRuleSet.is_valid_cql3_name(name):
1633
+ return name
1634
+ return "'%s'" % name
1635
+
1636
+ # disable completion for CREATE ROLE.
1637
+ if ctxt.matched[0][1].upper() == 'CREATE':
1638
+ return [Hint('<rolename>')]
1639
+
1640
+ session = cass.session
1641
+ return [maybe_quote(row[0].replace("'", "''")) for row in session.execute("LIST ROLES")]
1642
+
1643
+
1644
+ syntax_rules += r'''
1645
+ <createTriggerStatement> ::= "CREATE" "TRIGGER" ( "IF" "NOT" "EXISTS" )? <cident>
1646
+ "ON" cf=<columnFamilyName> "USING" class=<stringLiteral>
1647
+ ;
1648
+ <dropTriggerStatement> ::= "DROP" "TRIGGER" ( "IF" "EXISTS" )? triggername=<cident>
1649
+ "ON" cf=<columnFamilyName>
1650
+ ;
1651
+ '''
1652
+ explain_completion('createTriggerStatement', 'class', '\'fully qualified class name\'')
1653
+
1654
+
1655
+ def get_trigger_names(ctxt, cass):
1656
+ ks = ctxt.get_binding('ksname', None)
1657
+ if ks is not None:
1658
+ ks = dequote_name(ks)
1659
+ return cass.get_trigger_names(ks)
1660
+
1661
+
1662
+ @completer_for('dropTriggerStatement', 'triggername')
1663
+ def drop_trigger_completer(ctxt, cass):
1664
+ names = get_trigger_names(ctxt, cass)
1665
+ return list(map(maybe_escape_name, names))
1666
+
1667
+
1668
+ # END SYNTAX/COMPLETION RULE DEFINITIONS
1669
+
1670
+ CqlRuleSet.append_rules(syntax_rules)