Repository: cassandra Updated Branches: refs/heads/trunk adffb3602 -> 74647a8cc
cqlsh does not automatically downgrade CQL version patch by Yusuke Takata and Stefania Alborghetti; reviewed by Stefania Alborghetti and Tyler Hobbs for CASSANDRA-12150 Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/74647a8c Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/74647a8c Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/74647a8c Branch: refs/heads/trunk Commit: 74647a8cc5b18b86ee5cfdb071a8644630a1e7f3 Parents: adffb36 Author: Yusuke Takata <ytak...@yahoo-corp.jp> Authored: Mon Jul 11 09:56:23 2016 +0800 Committer: Stefania Alborghetti <stefania.alborghe...@datastax.com> Committed: Wed Jul 13 10:00:21 2016 +0800 ---------------------------------------------------------------------- CHANGES.txt | 1 + NEWS.txt | 5 ++ bin/cqlsh.py | 22 +++--- pylib/cqlshlib/test/cassconnect.py | 8 +-- pylib/cqlshlib/test/test_cqlsh_completion.py | 2 +- pylib/cqlshlib/test/test_cqlsh_output.py | 86 ++++++++++------------- 6 files changed, 60 insertions(+), 64 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cassandra/blob/74647a8c/CHANGES.txt ---------------------------------------------------------------------- diff --git a/CHANGES.txt b/CHANGES.txt index df07ba0..f63bd2b 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,4 +1,5 @@ 3.10 + * cqlsh does not automatically downgrade CQL version (CASSANDRA-12150) * Omit (de)serialization of state variable in UDAs (CASSANDRA-9613) * Create a system table to expose prepared statements (CASSANDRA-8831) * Reuse DataOutputBuffer from ColumnIndex (CASSANDRA-11970) http://git-wip-us.apache.org/repos/asf/cassandra/blob/74647a8c/NEWS.txt ---------------------------------------------------------------------- diff --git a/NEWS.txt b/NEWS.txt index 52eee1a..fd6f005 100644 --- a/NEWS.txt +++ b/NEWS.txt @@ -24,6 +24,11 @@ New features previously prepared statements - i.e. in many cases clients do not need to re-prepare statements against restarted nodes. + - cqlsh can now connect to older Cassandra versions by downgrading the native + protocol version. Please note that this is currently not part of our release + testing and, as a consequence, it is not guaranteed to work in all cases. + See CASSANDRA-12150 for more details. + Upgrading --------- - Nothing specific to 3.10 but please see previous versions upgrading section, http://git-wip-us.apache.org/repos/asf/cassandra/blob/74647a8c/bin/cqlsh.py ---------------------------------------------------------------------- diff --git a/bin/cqlsh.py b/bin/cqlsh.py index 3e03767..7877800 100644 --- a/bin/cqlsh.py +++ b/bin/cqlsh.py @@ -177,7 +177,6 @@ from cqlshlib.util import get_file_encoding_bomsize, trim_if_present DEFAULT_HOST = '127.0.0.1' DEFAULT_PORT = 9042 DEFAULT_SSL = False -DEFAULT_CQLVER = '3.4.2' DEFAULT_PROTOCOL_VERSION = 4 DEFAULT_CONNECT_TIMEOUT_SECONDS = 5 DEFAULT_REQUEST_TIMEOUT_SECONDS = 10 @@ -219,8 +218,9 @@ parser.add_option('--debug', action='store_true', parser.add_option("--encoding", help="Specify a non-default encoding for output." + " (Default: %s)" % (UTF8,)) parser.add_option("--cqlshrc", help="Specify an alternative cqlshrc file location.") -parser.add_option('--cqlversion', default=DEFAULT_CQLVER, - help='Specify a particular CQL version (default: %default).' +parser.add_option('--cqlversion', default=None, + help='Specify a particular CQL version, ' + 'by default the highest version supported by the server will be used.' ' Examples: "3.0.3", "3.1.0"') parser.add_option("-e", "--execute", help='Execute the statement and quit.') parser.add_option("--connect-timeout", default=DEFAULT_CONNECT_TIMEOUT_SECONDS, dest='connect_timeout', @@ -662,7 +662,7 @@ class Shell(cmd.Cmd): def __init__(self, hostname, port, color=False, username=None, password=None, encoding=None, stdin=None, tty=True, completekey=DEFAULT_COMPLETEKEY, browser=None, use_conn=None, - cqlver=DEFAULT_CQLVER, keyspace=None, + cqlver=None, keyspace=None, tracing_enabled=False, expand_enabled=False, display_nanotime_format=DEFAULT_NANOTIME_FORMAT, display_timestamp_format=DEFAULT_TIMESTAMP_FORMAT, @@ -701,7 +701,6 @@ class Shell(cmd.Cmd): control_connection_timeout=connect_timeout, connect_timeout=connect_timeout) self.owns_connection = not use_conn - self.set_expanded_cql_version(cqlver) if keyspace: self.session = self.conn.connect(keyspace) @@ -730,6 +729,7 @@ class Shell(cmd.Cmd): self.session.row_factory = ordered_dict_factory self.session.default_consistency_level = cassandra.ConsistencyLevel.ONE self.get_connection_versions() + self.set_expanded_cql_version(self.connection_versions['cql']) self.current_keyspace = keyspace @@ -2456,7 +2456,7 @@ def read_options(cmdlineargs, environment): optvalues.encoding = option_with_default(configs.get, 'ui', 'encoding', UTF8) optvalues.tty = option_with_default(configs.getboolean, 'ui', 'tty', sys.stdin.isatty()) - optvalues.cqlversion = option_with_default(configs.get, 'cql', 'version', DEFAULT_CQLVER) + optvalues.cqlversion = option_with_default(configs.get, 'cql', 'version', None) optvalues.connect_timeout = option_with_default(configs.getint, 'connection', 'timeout', DEFAULT_CONNECT_TIMEOUT_SECONDS) optvalues.request_timeout = option_with_default(configs.getint, 'connection', 'request_timeout', DEFAULT_REQUEST_TIMEOUT_SECONDS) optvalues.execute = None @@ -2500,11 +2500,11 @@ def read_options(cmdlineargs, environment): else: options.color = should_use_color() - options.cqlversion, cqlvertup = full_cql_version(options.cqlversion) - if cqlvertup[0] < 3: - parser.error('%r is not a supported CQL version.' % options.cqlversion) - else: - options.cqlmodule = cql3handling + if options.cqlversion is not None: + options.cqlversion, cqlvertup = full_cql_version(options.cqlversion) + if cqlvertup[0] < 3: + parser.error('%r is not a supported CQL version.' % options.cqlversion) + options.cqlmodule = cql3handling try: port = int(port) http://git-wip-us.apache.org/repos/asf/cassandra/blob/74647a8c/pylib/cqlshlib/test/cassconnect.py ---------------------------------------------------------------------- diff --git a/pylib/cqlshlib/test/cassconnect.py b/pylib/cqlshlib/test/cassconnect.py index 94910a6..4c80335 100644 --- a/pylib/cqlshlib/test/cassconnect.py +++ b/pylib/cqlshlib/test/cassconnect.py @@ -24,15 +24,13 @@ from .run_cqlsh import run_cqlsh, call_cqlsh test_keyspace_init = os.path.join(rundir, 'test_keyspace_init.cql') -def get_cassandra_connection(cql_version=cqlsh.DEFAULT_CQLVER): - if cql_version is None: - cql_version = cqlsh.DEFAULT_CQLVER +def get_cassandra_connection(cql_version=None): conn = cql((TEST_HOST,), TEST_PORT, cql_version=cql_version, load_balancing_policy=policy) # until the cql lib does this for us conn.cql_version = cql_version return conn -def get_cassandra_cursor(cql_version=cqlsh.DEFAULT_CQLVER): +def get_cassandra_cursor(cql_version=None): return get_cassandra_connection(cql_version=cql_version).cursor() TEST_KEYSPACES_CREATED = [] @@ -83,7 +81,7 @@ def remove_test_db(): c.execute('DROP KEYSPACE %s' % quote_name(TEST_KEYSPACES_CREATED.pop(-1))) @contextlib.contextmanager -def cassandra_connection(cql_version=cqlsh.DEFAULT_CQLVER): +def cassandra_connection(cql_version=None): """ Make a Cassandra CQL connection with the given CQL version and get a cursor for it, and optionally connect to a given keyspace. http://git-wip-us.apache.org/repos/asf/cassandra/blob/74647a8c/pylib/cqlshlib/test/test_cqlsh_completion.py ---------------------------------------------------------------------- diff --git a/pylib/cqlshlib/test/test_cqlsh_completion.py b/pylib/cqlshlib/test/test_cqlsh_completion.py index 8485ff0..33fe07c 100644 --- a/pylib/cqlshlib/test/test_cqlsh_completion.py +++ b/pylib/cqlshlib/test/test_cqlsh_completion.py @@ -42,7 +42,7 @@ completion_separation_re = re.compile(r'\s+') class CqlshCompletionCase(BaseTestCase): def setUp(self): - self.cqlsh_runner = testrun_cqlsh(cqlver=cqlsh.DEFAULT_CQLVER, env={'COLUMNS': '100000'}) + self.cqlsh_runner = testrun_cqlsh(cqlver=None, env={'COLUMNS': '100000'}) self.cqlsh = self.cqlsh_runner.__enter__() def tearDown(self): http://git-wip-us.apache.org/repos/asf/cassandra/blob/74647a8c/pylib/cqlshlib/test/test_cqlsh_output.py ---------------------------------------------------------------------- diff --git a/pylib/cqlshlib/test/test_cqlsh_output.py b/pylib/cqlshlib/test/test_cqlsh_output.py index c54792d..a6290ff 100644 --- a/pylib/cqlshlib/test/test_cqlsh_output.py +++ b/pylib/cqlshlib/test/test_cqlsh_output.py @@ -67,13 +67,6 @@ class TestCqlshOutput(BaseTestCase): 'Actually got: %s\ncolor code: %s' % (tags, coloredtext.colored_version(), coloredtext.colortags())) - def assertCqlverQueriesGiveColoredOutput(self, queries_and_expected_outputs, - cqlver=(cqlsh.DEFAULT_CQLVER,), **kwargs): - if not isinstance(cqlver, (tuple, list)): - cqlver = (cqlver,) - for ver in cqlver: - self.assertQueriesGiveColoredOutput(queries_and_expected_outputs, cqlver=ver, **kwargs) - def assertQueriesGiveColoredOutput(self, queries_and_expected_outputs, **kwargs): """ Allow queries and expected output to be specified in structured tuples, @@ -133,7 +126,7 @@ class TestCqlshOutput(BaseTestCase): self.assertHasColors(c.read_to_next_prompt()) def test_count_output(self): - self.assertCqlverQueriesGiveColoredOutput(( + self.assertQueriesGiveColoredOutput(( ('select count(*) from has_all_types;', """ count MMMMM @@ -198,7 +191,7 @@ class TestCqlshOutput(BaseTestCase): (1 rows) nnnnnnnn """), - ), cqlver=cqlsh.DEFAULT_CQLVER) + )) q = 'select COUNT(*) FROM twenty_rows_composite_table limit 1000000;' self.assertQueriesGiveColoredOutput(( @@ -214,10 +207,10 @@ class TestCqlshOutput(BaseTestCase): (1 rows) nnnnnnnn """), - ), cqlver=cqlsh.DEFAULT_CQLVER) + )) def test_static_cf_output(self): - self.assertCqlverQueriesGiveColoredOutput(( + self.assertQueriesGiveColoredOutput(( ("select a, b from twenty_rows_table where a in ('1', '13', '2');", """ a | b RR MM @@ -234,7 +227,7 @@ class TestCqlshOutput(BaseTestCase): (3 rows) nnnnnnnn """), - ), cqlver=cqlsh.DEFAULT_CQLVER) + )) self.assertQueriesGiveColoredOutput(( ('select * from dynamic_columns;', """ @@ -257,11 +250,11 @@ class TestCqlshOutput(BaseTestCase): (5 rows) nnnnnnnn """), - ), cqlver=cqlsh.DEFAULT_CQLVER) + )) def test_empty_cf_output(self): # we print the header after CASSANDRA-6910 - self.assertCqlverQueriesGiveColoredOutput(( + self.assertQueriesGiveColoredOutput(( ('select * from empty_table;', """ lonelykey | lonelycol RRRRRRRRR MMMMMMMMM @@ -270,7 +263,7 @@ class TestCqlshOutput(BaseTestCase): (0 rows) """), - ), cqlver=cqlsh.DEFAULT_CQLVER) + )) q = 'select * from has_all_types where num = 999;' @@ -284,7 +277,7 @@ class TestCqlshOutput(BaseTestCase): (0 rows) """), - ), cqlver=cqlsh.DEFAULT_CQLVER) + )) def test_columnless_key_output(self): q = "select a from twenty_rows_table where a in ('1', '2', '-9192');" @@ -304,10 +297,10 @@ class TestCqlshOutput(BaseTestCase): (2 rows) nnnnnnnn """), - ), cqlver=cqlsh.DEFAULT_CQLVER) + )) def test_numeric_output(self): - self.assertCqlverQueriesGiveColoredOutput(( + self.assertQueriesGiveColoredOutput(( ('''select intcol, bigintcol, varintcol \ from has_all_types \ where num in (0, 1, 2, 3, 4);''', """ @@ -353,7 +346,7 @@ class TestCqlshOutput(BaseTestCase): (5 rows) nnnnnnnn """), - ), cqlver=cqlsh.DEFAULT_CQLVER) + )) def test_timestamp_output(self): self.assertQueriesGiveColoredOutput(( @@ -390,7 +383,7 @@ class TestCqlshOutput(BaseTestCase): pass def test_boolean_output(self): - self.assertCqlverQueriesGiveColoredOutput(( + self.assertQueriesGiveColoredOutput(( ('select num, booleancol from has_all_types where num in (0, 1, 2, 3);', """ num | booleancol RRR MMMMMMMMMM @@ -409,11 +402,11 @@ class TestCqlshOutput(BaseTestCase): (4 rows) nnnnnnnn """), - ), cqlver=cqlsh.DEFAULT_CQLVER) + )) def test_null_output(self): # column with metainfo but no values - self.assertCqlverQueriesGiveColoredOutput(( + self.assertQueriesGiveColoredOutput(( ("select k, c, notthere from undefined_values_table where k in ('k1', 'k2');", """ k | c | notthere R M MMMMMMMM @@ -428,7 +421,7 @@ class TestCqlshOutput(BaseTestCase): (2 rows) nnnnnnnn """), - ), cqlver=cqlsh.DEFAULT_CQLVER) + )) # all-columns, including a metainfo column has no values (cql3) self.assertQueriesGiveColoredOutput(( @@ -446,10 +439,10 @@ class TestCqlshOutput(BaseTestCase): (2 rows) nnnnnnnn """), - ), cqlver=cqlsh.DEFAULT_CQLVER) + )) def test_string_output_ascii(self): - self.assertCqlverQueriesGiveColoredOutput(( + self.assertQueriesGiveColoredOutput(( ("select * from ascii_with_special_chars where k in (0, 1, 2, 3);", r""" k | val R MMM @@ -468,7 +461,7 @@ class TestCqlshOutput(BaseTestCase): (4 rows) nnnnnnnn """), - ), cqlver=cqlsh.DEFAULT_CQLVER) + )) def test_string_output_utf8(self): # many of these won't line up visually here, to keep the source code @@ -477,7 +470,7 @@ class TestCqlshOutput(BaseTestCase): # terminals, but the color-checking machinery here will still treat # it as one character, so those won't seem to line up visually either. - self.assertCqlverQueriesGiveColoredOutput(( + self.assertQueriesGiveColoredOutput(( ("select * from utf8_with_special_chars where k in (0, 1, 2, 3, 4, 5, 6);", u""" k | val R MMM @@ -502,10 +495,10 @@ class TestCqlshOutput(BaseTestCase): (7 rows) nnnnnnnn """.encode('utf-8')), - ), cqlver=cqlsh.DEFAULT_CQLVER, env={'LANG': 'en_US.UTF-8'}) + ), env={'LANG': 'en_US.UTF-8'}) def test_blob_output(self): - self.assertCqlverQueriesGiveColoredOutput(( + self.assertQueriesGiveColoredOutput(( ("select num, blobcol from has_all_types where num in (0, 1, 2, 3);", r""" num | blobcol RRR MMMMMMM @@ -524,10 +517,10 @@ class TestCqlshOutput(BaseTestCase): (4 rows) nnnnnnnn """), - ), cqlver=cqlsh.DEFAULT_CQLVER) + )) def test_prompt(self): - with testrun_cqlsh(tty=True, keyspace=None, cqlver=cqlsh.DEFAULT_CQLVER) as c: + with testrun_cqlsh(tty=True, keyspace=None) as c: self.assertTrue(c.output_header.splitlines()[-1].endswith('cqlsh> ')) c.send('\n') @@ -559,8 +552,7 @@ class TestCqlshOutput(BaseTestCase): "RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR") def test_describe_keyspace_output(self): - fullcqlver = cqlsh.DEFAULT_CQLVER - with testrun_cqlsh(tty=True, cqlver=fullcqlver) as c: + with testrun_cqlsh(tty=True) as c: ks = get_test_keyspace() qks = quote_name(ks) for cmd in ('describe keyspace', 'desc keyspace'): @@ -568,7 +560,7 @@ class TestCqlshOutput(BaseTestCase): for semicolon in ('', ';'): fullcmd = cmd + (' ' if givename else '') + givename + semicolon desc = c.cmd_and_response(fullcmd) - self.check_describe_keyspace_output(desc, givename or qks, fullcqlver) + self.check_describe_keyspace_output(desc, givename or qks) # try to actually execute that last keyspace description, with a # new keyspace name @@ -577,7 +569,7 @@ class TestCqlshOutput(BaseTestCase): statements = split_cql_commands(copy_desc) do_drop = True - with cassandra_cursor(cql_version=fullcqlver) as curs: + with cassandra_cursor() as curs: try: for stmt in statements: cqlshlog.debug('TEST EXEC: %s' % stmt) @@ -587,7 +579,7 @@ class TestCqlshOutput(BaseTestCase): if do_drop: curs.execute('drop keyspace %s' % quote_name(new_ks_name)) - def check_describe_keyspace_output(self, output, qksname, fullcqlver): + def check_describe_keyspace_output(self, output, qksname): expected_bits = [r'(?im)^CREATE KEYSPACE %s WITH\b' % re.escape(qksname), r';\s*$', r'\breplication = {\'class\':'] @@ -635,7 +627,7 @@ class TestCqlshOutput(BaseTestCase): """ % quote_name(get_test_keyspace())) - with testrun_cqlsh(tty=True, cqlver=cqlsh.DEFAULT_CQLVER) as c: + with testrun_cqlsh(tty=True) as c: for cmdword in ('describe table', 'desc columnfamily'): for semicolon in (';', ''): output = c.cmd_and_response('%s has_all_types%s' % (cmdword, semicolon)) @@ -653,7 +645,7 @@ class TestCqlshOutput(BaseTestCase): ks = get_test_keyspace() - with testrun_cqlsh(tty=True, keyspace=None, cqlver=cqlsh.DEFAULT_CQLVER) as c: + with testrun_cqlsh(tty=True, keyspace=None) as c: # when not in a keyspace for cmdword in ('DESCRIBE COLUMNFAMILIES', 'desc tables'): @@ -704,7 +696,7 @@ class TestCqlshOutput(BaseTestCase): \n ''' - with testrun_cqlsh(tty=True, keyspace=None, cqlver=cqlsh.DEFAULT_CQLVER) as c: + with testrun_cqlsh(tty=True, keyspace=None) as c: # not in a keyspace for semicolon in ('', ';'): @@ -792,7 +784,7 @@ class TestCqlshOutput(BaseTestCase): pass def test_user_types_output(self): - self.assertCqlverQueriesGiveColoredOutput(( + self.assertQueriesGiveColoredOutput(( ("select addresses from users;", r""" addresses MMMMMMMMM @@ -807,8 +799,8 @@ class TestCqlshOutput(BaseTestCase): (2 rows) nnnnnnnn """), - ), cqlver=cqlsh.DEFAULT_CQLVER) - self.assertCqlverQueriesGiveColoredOutput(( + )) + self.assertQueriesGiveColoredOutput(( ("select phone_numbers from users;", r""" phone_numbers MMMMMMMMMMMMM @@ -823,10 +815,10 @@ class TestCqlshOutput(BaseTestCase): (2 rows) nnnnnnnn """), - ), cqlver=cqlsh.DEFAULT_CQLVER) + )) def test_user_types_with_collections(self): - self.assertCqlverQueriesGiveColoredOutput(( + self.assertQueriesGiveColoredOutput(( ("select info from songs;", r""" info MMMM @@ -839,8 +831,8 @@ class TestCqlshOutput(BaseTestCase): (1 rows) nnnnnnnn """), - ), cqlver=cqlsh.DEFAULT_CQLVER) - self.assertCqlverQueriesGiveColoredOutput(( + )) + self.assertQueriesGiveColoredOutput(( ("select tags from songs;", r""" tags MMMM @@ -853,4 +845,4 @@ class TestCqlshOutput(BaseTestCase): (1 rows) nnnnnnnn """), - ), cqlver=cqlsh.DEFAULT_CQLVER) + ))