cqlsh: update recognized syntax

Patch by paul cannon and Aleksey Yeschenko, reviewed by brandonwilliams
for CASSANDRA-4488
This commit is contained in:
Brandon Williams 2012-10-08 11:10:09 -05:00
parent e8438b8084
commit 2f979ed60f
4 changed files with 837 additions and 169 deletions

View File

@ -441,6 +441,14 @@ class Shell(cmd.Cmd):
self.cursor = self.conn.cursor()
self.get_connection_versions()
# use 3.0.0-beta1 syntax if explicitly requested, or if using
# cassandra < 1.2. this only affects use of cql3; cql2 syntax
# in either case is the same.
if self.cassandraver_atleast(1, 2) and not self.is_cql3_beta():
cql3handling.use_post_3_0_0_syntax()
else:
cql3handling.use_pre_3_0_0_syntax()
self.current_keyspace = keyspace
self.color = color
@ -473,6 +481,9 @@ class Shell(cmd.Cmd):
self.cql_version = ver
self.cql_ver_tuple = vertuple
def is_cql3_beta(self):
return self.cql_ver_tuple == (3, 0, 0, 'beta1')
def cqlver_atleast(self, major, minor=0, patch=0):
return self.cql_ver_tuple[:3] >= (major, minor, patch)
@ -596,6 +607,11 @@ class Shell(cmd.Cmd):
raise ColumnFamilyNotFound("Unconfigured column family %r" % (cfname,))
def get_columnfamily_names(self, ksname=None):
if self.cqlver_atleast(3) and ksname not in SYSTEM_KEYSPACES:
# since cql3 tables may be left out of thrift results, but
# info on tables in system keyspaces still aren't included
# in system.schema_*
return self.get_columnfamily_names_cql3(ksname=ksname)
return [c.name for c in self.get_columnfamilies(ksname)]
def get_index_names(self, ksname=None):
@ -681,6 +697,18 @@ class Shell(cmd.Cmd):
# ===== cql3-dependent parts =====
def get_columnfamily_names_cql3(self, ksname=None):
if ksname is None:
ksname = self.current_keyspace
if self.cassandraver_atleast(1, 2):
cf_q = """select columnfamily_name from system.schema_columnfamilies
where keyspace_name=:ks"""
else:
cf_q = """select "columnfamily" from system.schema_columnfamilies
where "keyspace"=:ks"""
self.cursor.execute(cf_q, {'ks': ksname})
return [row[0] for row in self.cursor.fetchall()]
def get_columnfamily_layout(self, ksname, cfname):
if ksname is None:
ksname = self.current_keyspace
@ -853,7 +881,9 @@ class Shell(cmd.Cmd):
return self.perform_statement(cqlruleset.cql_extract_orig(tokens, srcstr))
def handle_parse_error(self, cmdword, tokens, parsed, srcstr):
if cmdword.lower() == 'select':
if cmdword.lower() in ('select', 'insert', 'update', 'delete', 'truncate',
'create', 'drop', 'alter', 'grant', 'revoke',
'batch', 'list'):
# hey, maybe they know about some new syntax we don't. type
# assumptions won't work, but maybe the query will.
return self.perform_statement(cqlruleset.cql_extract_orig(tokens, srcstr))
@ -1105,10 +1135,20 @@ class Shell(cmd.Cmd):
def print_recreate_keyspace(self, ksdef, out):
stratclass = trim_if_present(ksdef.strategy_class, 'org.apache.cassandra.locator.')
ksname = self.cql_protect_name(ksdef.name)
out.write("CREATE KEYSPACE %s WITH strategy_class = %s"
% (ksname, self.cql_protect_value(stratclass)))
for opname, opval in ksdef.strategy_options.iteritems():
out.write("\n AND strategy_options:%s = %s" % (opname, self.cql_protect_value(opval)))
if self.cqlver_atleast(3) and not self.is_cql3_beta():
out.write("CREATE KEYSPACE %s WITH replication = {\n" % ksname)
out.write(" 'class': %s" % self.cql_protect_value(stratclass))
for opname, opval in ksdef.strategy_options.iteritems():
out.write(",\n %s: %s" % (self.cql_protect_value(opname),
self.cql_protect_value(opval)))
out.write("\n}")
if not ksdef.durable_writes:
out.write(" AND durable_writes = 'false'")
else:
out.write("CREATE KEYSPACE %s WITH strategy_class = %s"
% (ksname, self.cql_protect_value(stratclass)))
for opname, opval in ksdef.strategy_options.iteritems():
out.write("\n AND strategy_options:%s = %s" % (opname, self.cql_protect_value(opval)))
out.write(';\n')
if ksdef.cf_defs:
@ -1224,24 +1264,42 @@ class Shell(cmd.Cmd):
out.write(' WITH COMPACT STORAGE')
joiner = 'AND'
# TODO: this should display CLUSTERING ORDER BY information too.
# work out how to determine that from a layout.
cf_opts = []
for option in cqlruleset.columnfamily_layout_options:
optval = getattr(layout, option, None)
for cql3option, layoutoption in cqlruleset.columnfamily_layout_options:
if layoutoption is None:
layoutoption = cql3option
optval = getattr(layout, layoutoption, None)
if optval is None:
continue
if option == 'row_cache_provider':
optval = trim_if_present(optval, 'org.apache.cassandra.cache.')
elif option == 'compaction_strategy_class':
elif layoutoption == 'compaction_strategy_class':
optval = trim_if_present(optval, 'org.apache.cassandra.db.compaction.')
cf_opts.append((option, self.cql_protect_value(optval)))
for option, _ in cqlruleset.columnfamily_layout_map_options:
optmap = getattr(layout, option, {})
for k, v in optmap.items():
if option == 'compression_parameters' and k == 'sstable_compression':
v = trim_if_present(v, 'org.apache.cassandra.io.compress.')
cf_opts.append(('%s:%s' % (option, k.encode('ascii')), self.cql_protect_value(v)))
cf_opts.append((cql3option, self.cql_protect_value(optval)))
for cql3option, layoutoption, _ in cqlruleset.columnfamily_layout_map_options:
if layoutoption is None:
layoutoption = cql3option
optmap = getattr(layout, layoutoption, {})
if layoutoption == 'compression_parameters':
compclass = optmap.get('sstable_compression')
if compclass is not None:
optmap['sstable_compression'] = \
trim_if_present(compclass, 'org.apache.cassandra.io.compress.')
if self.cqlver_atleast(3) and not self.is_cql3_beta():
cf_opts.append((cql3option, optmap))
else:
for k, v in optmap.items():
cf_opts.append(('%s:%s' % (cql3option, k.encode('ascii')),
self.cql_protect_value(v)))
if cf_opts:
for optname, optval in cf_opts:
if isinstance(optval, dict):
optval = '{%s}' % ', '.join(['%s: %s' % (self.cql_protect_value(k),
self.cql_protect_value(v))
for (k, v) in optval.items()])
if optval == '{}':
continue
out.write(" %s\n %s=%s" % (joiner, optname, optval))
joiner = 'AND'
out.write(";\n")

File diff suppressed because it is too large Load Diff

View File

@ -24,6 +24,8 @@ from cql import cqltypes
Hint = pylexotron.Hint
SYSTEM_KEYSPACES = ('system',)
class CqlParsingRuleSet(pylexotron.ParsingRuleSet):
keywords = set((
'select', 'from', 'where', 'and', 'key', 'insert', 'update', 'with',
@ -84,6 +86,13 @@ class CqlParsingRuleSet(pylexotron.ParsingRuleSet):
'NetworkTopologyStrategy'
)
replication_factor_strategies = (
'SimpleStrategy',
'org.apache.cassandra.locator.SimpleStrategy',
'OldNetworkTopologyStrategy',
'org.apache.cassandra.locator.OldNetworkTopologyStrategy'
)
consistency_levels = (
'ANY',
'ONE',
@ -385,7 +394,7 @@ class CqlParsingRuleSet(pylexotron.ParsingRuleSet):
cqlword = cqlword.strip()
if cqlword == '':
return cqlword
if cqlword[0] == "'":
if cqlword[0] == "'" and cqlword[-1] == "'":
cqlword = cqlword[1:-1].replace("''", "'")
return cqlword
@ -736,10 +745,7 @@ def create_ks_opt_completer(ctxt, cass):
return ['strategy_class =']
vals = ctxt.get_binding('optval')
stratclass = dequote_value(vals[stratopt])
if stratclass in ('SimpleStrategy',
'org.apache.cassandra.locator.SimpleStrategy',
'OldNetworkTopologyStrategy',
'org.apache.cassandra.locator.OldNetworkTopologyStrategy'):
if stratclass in CqlRuleSet.replication_factor_strategies:
return ['strategy_options:replication_factor =']
return [Hint('<strategy_option_name>')]

View File

@ -118,19 +118,24 @@ class matcher:
@staticmethod
def try_registered_completion(ctxt, symname, completions):
debugging = ctxt.get_binding('*DEBUG*', False)
if ctxt.remainder or completions is None:
return False
try:
completer = ctxt.get_completer(symname)
except KeyError:
return False
if debugging:
print "Trying completer %r with %r" % (completer, ctxt)
try:
new_compls = completer(ctxt)
except Exception:
if ctxt.get_binding('*DEBUG*', False):
if debugging:
import traceback
traceback.print_exc()
return False
if debugging:
print "got %r" % (new_compls,)
completions.update(new_compls)
return True
@ -291,6 +296,9 @@ class terminal_type_matcher(matcher):
self.submatcher.match(ctxt, completions)
return []
def __repr__(self):
return '%s(%r, %r)' % (self.__class__.__name__, self.tokentype, self.submatcher)
class ParsingRuleSet:
RuleSpecScanner = SaferScanner([
(r'::=', lambda s,t: t),