mirror of https://github.com/apache/cassandra
Merge branch 'cassandra-2.1' into trunk
Conflicts: bin/cqlsh
This commit is contained in:
commit
840d9a6632
88
bin/cqlsh
88
bin/cqlsh
|
|
@ -36,7 +36,7 @@ description = "CQL Shell for Apache Cassandra"
|
|||
version = "5.0.1"
|
||||
|
||||
from StringIO import StringIO
|
||||
from contextlib import contextmanager, closing
|
||||
from contextlib import contextmanager
|
||||
from glob import glob
|
||||
|
||||
import cmd
|
||||
|
|
@ -79,6 +79,7 @@ if myplatform == 'Linux':
|
|||
if os.environ.get('CQLSH_NO_BUNDLED', ''):
|
||||
ZIPLIB_DIRS = ()
|
||||
|
||||
|
||||
def find_zip(libprefix):
|
||||
for ziplibdir in ZIPLIB_DIRS:
|
||||
zips = glob(os.path.join(ziplibdir, libprefix + '*.zip'))
|
||||
|
|
@ -111,7 +112,6 @@ from cassandra.cluster import Cluster, PagedResult
|
|||
from cassandra.query import SimpleStatement, ordered_dict_factory
|
||||
from cassandra.policies import WhiteListRoundRobinPolicy
|
||||
from cassandra.protocol import QueryMessage, ResultMessage
|
||||
from cassandra.marshal import int16_pack, int32_pack, uint64_pack
|
||||
from cassandra.metadata import protect_name, protect_names, protect_value, KeyspaceMetadata, TableMetadata, ColumnMetadata
|
||||
from cassandra.auth import PlainTextAuthProvider
|
||||
|
||||
|
|
@ -145,6 +145,9 @@ if readline is not None and readline.__doc__ is not None and 'libedit' in readli
|
|||
else:
|
||||
DEFAULT_COMPLETEKEY = 'tab'
|
||||
|
||||
cqldocs = None
|
||||
cqlruleset = None
|
||||
|
||||
epilog = """Connects to %(DEFAULT_HOST)s:%(DEFAULT_PORT)d by default. These
|
||||
defaults can be changed by setting $CQLSH_HOST and/or $CQLSH_PORT. When a
|
||||
host (and optional port number) are given on the command line, they take
|
||||
|
|
@ -227,13 +230,17 @@ my_commands_ending_with_newline = (
|
|||
'quit'
|
||||
)
|
||||
|
||||
|
||||
cqlsh_syntax_completers = []
|
||||
|
||||
|
||||
def cqlsh_syntax_completer(rulename, termname):
|
||||
def registrator(f):
|
||||
cqlsh_syntax_completers.append((rulename, termname, f))
|
||||
return f
|
||||
return registrator
|
||||
|
||||
|
||||
cqlsh_extra_syntax_rules = r'''
|
||||
<cqlshCommand> ::= <CQL_Statement>
|
||||
| <specialCommand> ( ";" | "\n" )
|
||||
|
|
@ -325,13 +332,15 @@ cqlsh_extra_syntax_rules = r'''
|
|||
<qmark> ::= "?" ;
|
||||
'''
|
||||
|
||||
|
||||
@cqlsh_syntax_completer('helpCommand', 'topic')
|
||||
def complete_help(ctxt, cqlsh):
|
||||
return sorted([ t.upper() for t in cqldocs.get_help_topics() + cqlsh.get_help_topics() ])
|
||||
return sorted([t.upper() for t in cqldocs.get_help_topics() + cqlsh.get_help_topics()])
|
||||
|
||||
|
||||
def complete_source_quoted_filename(ctxt, cqlsh):
|
||||
partial = ctxt.get_binding('partial', '')
|
||||
head, tail = os.path.split(partial)
|
||||
partial_path = ctxt.get_binding('partial', '')
|
||||
head, tail = os.path.split(partial_path)
|
||||
exhead = os.path.expanduser(head)
|
||||
try:
|
||||
contents = os.listdir(exhead or '.')
|
||||
|
|
@ -346,21 +355,22 @@ def complete_source_quoted_filename(ctxt, cqlsh):
|
|||
annotated.append(match)
|
||||
return annotated
|
||||
|
||||
cqlsh_syntax_completer('sourceCommand', 'fname') \
|
||||
(complete_source_quoted_filename)
|
||||
cqlsh_syntax_completer('captureCommand', 'fname') \
|
||||
(complete_source_quoted_filename)
|
||||
|
||||
cqlsh_syntax_completer('sourceCommand', 'fname')(complete_source_quoted_filename)
|
||||
cqlsh_syntax_completer('captureCommand', 'fname')(complete_source_quoted_filename)
|
||||
|
||||
|
||||
@cqlsh_syntax_completer('copyCommand', 'fname')
|
||||
def copy_fname_completer(ctxt, cqlsh):
|
||||
lasttype = ctxt.get_binding('*LASTTYPE*')
|
||||
if lasttype == 'unclosedString':
|
||||
return complete_source_quoted_filename(ctxt, cqlsh)
|
||||
partial = ctxt.get_binding('partial')
|
||||
if partial == '':
|
||||
partial_path = ctxt.get_binding('partial')
|
||||
if partial_path == '':
|
||||
return ["'"]
|
||||
return ()
|
||||
|
||||
|
||||
@cqlsh_syntax_completer('copyCommand', 'colnames')
|
||||
def complete_copy_column_names(ctxt, cqlsh):
|
||||
existcols = map(cqlsh.cql_unprotect_name, ctxt.get_binding('colnames', ()))
|
||||
|
|
@ -371,8 +381,10 @@ def complete_copy_column_names(ctxt, cqlsh):
|
|||
return [colnames[0]]
|
||||
return set(colnames[1:]) - set(existcols)
|
||||
|
||||
|
||||
COPY_OPTIONS = ('DELIMITER', 'QUOTE', 'ESCAPE', 'HEADER', 'ENCODING', 'NULL')
|
||||
|
||||
|
||||
@cqlsh_syntax_completer('copyOption', 'optnames')
|
||||
def complete_copy_options(ctxt, cqlsh):
|
||||
optnames = map(str.upper, ctxt.get_binding('optnames', ()))
|
||||
|
|
@ -382,6 +394,7 @@ def complete_copy_options(ctxt, cqlsh):
|
|||
opts -= ('ENCODING',)
|
||||
return opts
|
||||
|
||||
|
||||
@cqlsh_syntax_completer('copyOption', 'optvals')
|
||||
def complete_copy_opt_values(ctxt, cqlsh):
|
||||
optnames = ctxt.get_binding('optnames', ())
|
||||
|
|
@ -390,21 +403,27 @@ def complete_copy_opt_values(ctxt, cqlsh):
|
|||
return ['true', 'false']
|
||||
return [cqlhandling.Hint('<single_character_string>')]
|
||||
|
||||
|
||||
class NoKeyspaceError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class KeyspaceNotFound(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class ColumnFamilyNotFound(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class VersionNotSupported(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class UserTypeNotFound(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class DecodeError(Exception):
|
||||
verb = 'decode'
|
||||
|
||||
|
|
@ -426,9 +445,11 @@ class DecodeError(Exception):
|
|||
def __repr__(self):
|
||||
return '<%s %s>' % (self.__class__.__name__, self.message())
|
||||
|
||||
|
||||
class FormatError(DecodeError):
|
||||
verb = 'format'
|
||||
|
||||
|
||||
def full_cql_version(ver):
|
||||
while ver.count('.') < 2:
|
||||
ver += '.0'
|
||||
|
|
@ -436,6 +457,7 @@ def full_cql_version(ver):
|
|||
vertuple = tuple(map(int, ver_parts[0].split('.')) + [ver_parts[1]])
|
||||
return ver, vertuple
|
||||
|
||||
|
||||
def format_value(val, output_encoding, addcolor=False, date_time_format=None,
|
||||
float_precision=None, colormap=None, nullval=None):
|
||||
if isinstance(val, DecodeError):
|
||||
|
|
@ -447,6 +469,7 @@ def format_value(val, output_encoding, addcolor=False, date_time_format=None,
|
|||
addcolor=addcolor, nullval=nullval, date_time_format=date_time_format,
|
||||
float_precision=float_precision)
|
||||
|
||||
|
||||
def show_warning_without_quoting_line(message, category, filename, lineno, file=None, line=None):
|
||||
if file is None:
|
||||
file = sys.stderr
|
||||
|
|
@ -457,6 +480,7 @@ def show_warning_without_quoting_line(message, category, filename, lineno, file=
|
|||
warnings.showwarning = show_warning_without_quoting_line
|
||||
warnings.filterwarnings('always', category=cql3handling.UnexpectedTableStructure)
|
||||
|
||||
|
||||
def describe_interval(seconds):
|
||||
desc = []
|
||||
for length, unit in ((86400, 'day'), (3600, 'hour'), (60, 'minute')):
|
||||
|
|
@ -477,6 +501,7 @@ def describe_interval(seconds):
|
|||
def auto_format_udts():
|
||||
# when we see a new user defined type, set up the shell formatting for it
|
||||
udt_apply_params = cassandra.cqltypes.UserType.apply_parameters
|
||||
|
||||
def new_apply_params(cls, *args, **kwargs):
|
||||
udt_class = udt_apply_params(*args, **kwargs)
|
||||
formatter_for(udt_class.typename)(format_value_utype)
|
||||
|
|
@ -485,6 +510,7 @@ def auto_format_udts():
|
|||
cassandra.cqltypes.UserType.udt_apply_parameters = classmethod(new_apply_params)
|
||||
|
||||
make_udt_class = cassandra.cqltypes.UserType.make_udt_class
|
||||
|
||||
def new_make_udt_class(cls, *args, **kwargs):
|
||||
udt_class = make_udt_class(*args, **kwargs)
|
||||
formatter_for(udt_class.tuple_type.__name__)(format_value_utype)
|
||||
|
|
@ -665,9 +691,9 @@ class Shell(cmd.Cmd):
|
|||
# check column role and color appropriately
|
||||
if table_meta:
|
||||
if name in [col.name for col in table_meta.partition_key]:
|
||||
column_colors.default_factory = lambda : RED
|
||||
column_colors.default_factory = lambda: RED
|
||||
elif name in [col.name for col in table_meta.clustering_key]:
|
||||
column_colors.default_factory = lambda : CYAN
|
||||
column_colors.default_factory = lambda: CYAN
|
||||
return self.myformat_value(name, colormap=column_colors)
|
||||
|
||||
def report_connection(self):
|
||||
|
|
@ -769,7 +795,7 @@ class Shell(cmd.Cmd):
|
|||
ksmeta = self.get_keyspace_meta(ksname)
|
||||
|
||||
if tablename not in ksmeta.tables:
|
||||
if ksname == 'system_auth' and tablename in ['roles','role_permissions']:
|
||||
if ksname == 'system_auth' and tablename in ['roles', 'role_permissions']:
|
||||
self.get_fake_auth_table_meta(ksname, tablename)
|
||||
else:
|
||||
raise ColumnFamilyNotFound("Column family %r not found" % tablename)
|
||||
|
|
@ -793,7 +819,7 @@ class Shell(cmd.Cmd):
|
|||
table_meta.columns['resource'] = ColumnMetadata(table_meta, 'resource', cassandra.cqltypes.UTF8Type)
|
||||
table_meta.columns['permission'] = ColumnMetadata(table_meta, 'permission', cassandra.cqltypes.UTF8Type)
|
||||
else:
|
||||
raise ColumnFamilyNotFoundException("Column family %r not found" % tablename)
|
||||
raise ColumnFamilyNotFound("Column family %r not found" % tablename)
|
||||
|
||||
def get_usertypes_meta(self):
|
||||
data = self.session.execute("select * from system.schema_usertypes")
|
||||
|
|
@ -813,7 +839,7 @@ class Shell(cmd.Cmd):
|
|||
def reset_statement(self):
|
||||
self.reset_prompt()
|
||||
self.statement.truncate(0)
|
||||
self.empty_lines = 0;
|
||||
self.empty_lines = 0
|
||||
|
||||
def reset_prompt(self):
|
||||
if self.current_keyspace is None:
|
||||
|
|
@ -822,7 +848,7 @@ class Shell(cmd.Cmd):
|
|||
self.set_prompt(self.keyspace_prompt % self.current_keyspace, True)
|
||||
|
||||
def set_continue_prompt(self):
|
||||
if self.empty_lines >=3:
|
||||
if self.empty_lines >= 3:
|
||||
self.set_prompt("Statements are terminated with a ';'. You can press CTRL-C to cancel an incomplete statement.")
|
||||
self.empty_lines = 0
|
||||
return
|
||||
|
|
@ -881,7 +907,6 @@ class Shell(cmd.Cmd):
|
|||
return
|
||||
yield newline
|
||||
|
||||
|
||||
def cmdloop(self):
|
||||
"""
|
||||
Adapted from cmd.Cmd's version, because there is literally no way with
|
||||
|
|
@ -1023,7 +1048,7 @@ class Shell(cmd.Cmd):
|
|||
parsed = cqlruleset.cql_parse(query_string)[1]
|
||||
except IndexError:
|
||||
return None
|
||||
ks = self.cql_unprotect_name(parsed.get_binding('ksname', None))
|
||||
ks = self.cql_unprotect_name(parsed.get_binding('ksname', None))
|
||||
cf = self.cql_unprotect_name(parsed.get_binding('cfname'))
|
||||
return self.get_table_meta(ks, cf)
|
||||
|
||||
|
|
@ -1046,9 +1071,9 @@ class Shell(cmd.Cmd):
|
|||
if statement.query_string[:6].lower() == 'select':
|
||||
self.print_result(rows, self.parse_for_table_meta(statement.query_string))
|
||||
elif statement.query_string.lower().startswith("list users") or statement.query_string.lower().startswith("list roles"):
|
||||
self.print_result(rows, self.get_table_meta('system_auth','roles'))
|
||||
self.print_result(rows, self.get_table_meta('system_auth', 'roles'))
|
||||
elif statement.query_string.lower().startswith("list"):
|
||||
self.print_result(rows, self.get_table_meta('system_auth','role_permissions'))
|
||||
self.print_result(rows, self.get_table_meta('system_auth', 'role_permissions'))
|
||||
elif rows:
|
||||
# CAS INSERT/UPDATE
|
||||
self.writeresult("")
|
||||
|
|
@ -1126,7 +1151,7 @@ class Shell(cmd.Cmd):
|
|||
# stop if there are no rows
|
||||
if formatted_values is None:
|
||||
self.writeresult("")
|
||||
return;
|
||||
return
|
||||
|
||||
# print row data
|
||||
for row in formatted_values:
|
||||
|
|
@ -1178,7 +1203,6 @@ class Shell(cmd.Cmd):
|
|||
prevlines = self.statement.getvalue()
|
||||
wholestmt = prevlines + curline
|
||||
begidx = readline.get_begidx() + len(prevlines)
|
||||
endidx = readline.get_endidx() + len(prevlines)
|
||||
stuff_to_complete = wholestmt[:begidx]
|
||||
return cqlruleset.cql_complete(stuff_to_complete, text, cassandra_conn=self,
|
||||
debug=debug_completion, startsymbol='cqlshCommand')
|
||||
|
|
@ -1412,7 +1436,7 @@ class Shell(cmd.Cmd):
|
|||
fname = os.path.expanduser(self.cql_unprotect_value(fname))
|
||||
copyoptnames = map(str.lower, parsed.get_binding('optnames', ()))
|
||||
copyoptvals = map(self.cql_unprotect_value, parsed.get_binding('optvals', ()))
|
||||
cleancopyoptvals = [optval.decode('string-escape') for optval in copyoptvals]
|
||||
cleancopyoptvals = [optval.decode('string-escape') for optval in copyoptvals]
|
||||
opts = dict(zip(copyoptnames, cleancopyoptvals))
|
||||
|
||||
timestart = time.time()
|
||||
|
|
@ -1464,7 +1488,6 @@ class Shell(cmd.Cmd):
|
|||
try:
|
||||
if header:
|
||||
linesource.next()
|
||||
table_meta = self.get_table_meta(ks, cf)
|
||||
reader = csv.reader(linesource, **dialect_options)
|
||||
|
||||
from multiprocessing import Process, Pipe, cpu_count
|
||||
|
|
@ -1980,7 +2003,7 @@ class Shell(cmd.Cmd):
|
|||
pdb.set_trace()
|
||||
|
||||
def get_help_topics(self):
|
||||
topics = [ t[3:] for t in dir(self) if t.startswith('do_') and getattr(self, t, None).__doc__]
|
||||
topics = [t[3:] for t in dir(self) if t.startswith('do_') and getattr(self, t, None).__doc__]
|
||||
for hide_from_help in ('quit',):
|
||||
topics.remove(hide_from_help)
|
||||
return topics
|
||||
|
|
@ -1998,9 +2021,9 @@ class Shell(cmd.Cmd):
|
|||
"""
|
||||
topics = parsed.get_binding('topic', ())
|
||||
if not topics:
|
||||
shell_topics = [ t.upper() for t in self.get_help_topics() ]
|
||||
shell_topics = [t.upper() for t in self.get_help_topics()]
|
||||
self.print_topics("\nDocumented shell commands:", shell_topics, 15, 80)
|
||||
cql_topics = [ t.upper() for t in cqldocs.get_help_topics() ]
|
||||
cql_topics = [t.upper() for t in cqldocs.get_help_topics()]
|
||||
self.print_topics("CQL help topics:", cql_topics, 15, 80)
|
||||
return
|
||||
for t in topics:
|
||||
|
|
@ -2095,6 +2118,7 @@ def option_with_default(cparser_getter, section, option, default=None):
|
|||
except ConfigParser.Error:
|
||||
return default
|
||||
|
||||
|
||||
def raw_option_with_default(configs, section, option, default=None):
|
||||
"""
|
||||
Same (almost) as option_with_default() but won't do any string interpolation.
|
||||
|
|
@ -2105,6 +2129,7 @@ def raw_option_with_default(configs, section, option, default=None):
|
|||
except ConfigParser.Error:
|
||||
return default
|
||||
|
||||
|
||||
def should_use_color():
|
||||
if not sys.stdout.isatty():
|
||||
return False
|
||||
|
|
@ -2122,6 +2147,7 @@ def should_use_color():
|
|||
pass
|
||||
return True
|
||||
|
||||
|
||||
def read_options(cmdlineargs, environment):
|
||||
configs = ConfigParser.SafeConfigParser()
|
||||
configs.read(CONFIG_FILE)
|
||||
|
|
@ -2201,6 +2227,7 @@ def read_options(cmdlineargs, environment):
|
|||
|
||||
return options, hostname, port
|
||||
|
||||
|
||||
def setup_cqlruleset(cqlmodule):
|
||||
global cqlruleset
|
||||
cqlruleset = cqlmodule.CqlRuleSet
|
||||
|
|
@ -2209,10 +2236,12 @@ def setup_cqlruleset(cqlmodule):
|
|||
cqlruleset.completer_for(rulename, termname)(func)
|
||||
cqlruleset.commands_end_with_newline.update(my_commands_ending_with_newline)
|
||||
|
||||
|
||||
def setup_cqldocs(cqlmodule):
|
||||
global cqldocs
|
||||
cqldocs = cqlmodule.cqldocs
|
||||
|
||||
|
||||
def init_history():
|
||||
if readline is not None:
|
||||
try:
|
||||
|
|
@ -2224,6 +2253,7 @@ def init_history():
|
|||
delims += '.'
|
||||
readline.set_completer_delims(delims)
|
||||
|
||||
|
||||
def save_history():
|
||||
if readline is not None:
|
||||
try:
|
||||
|
|
@ -2231,6 +2261,7 @@ def save_history():
|
|||
except IOError:
|
||||
pass
|
||||
|
||||
|
||||
def main(options, hostname, port):
|
||||
setup_cqlruleset(options.cqlmodule)
|
||||
setup_cqldocs(options.cqlmodule)
|
||||
|
|
@ -2284,6 +2315,7 @@ def main(options, hostname, port):
|
|||
if batch_mode and shell.statement_error:
|
||||
sys.exit(2)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main(*read_options(sys.argv[1:], os.environ))
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue