diff --git a/test/cql-pytest/cassandra_tests/porting.py b/test/cql-pytest/cassandra_tests/porting.py index 070f6a7434..ffa010d7a2 100644 --- a/test/cql-pytest/cassandra_tests/porting.py +++ b/test/cql-pytest/cassandra_tests/porting.py @@ -121,9 +121,13 @@ def assert_invalid(cql, table, cmd, *args): # SyntaxException. assert_invalid_throw(cql, table, InvalidRequest, cmd, *args) +assertInvalid = assert_invalid + def assert_invalid_syntax(cql, table, cmd, *args): assert_invalid_throw(cql, table, SyntaxException, cmd, *args) +assertInvalidSyntax = assert_invalid_syntax + def assert_invalid_message(cql, table, message, cmd, *args): with pytest.raises(InvalidRequest, match=re.escape(message)): execute(cql, table, cmd, *args) @@ -156,11 +160,19 @@ def assert_invalid_throw_message_re(cql, table, message, typ, cmd, *args): def assert_row_count(result, expected): assert len(list(result)) == expected +assertRowCount = assert_row_count + def assert_empty(result): assert len(list(result)) == 0 assertEmpty = assert_empty +def assertArrayEquals(a, b): + assert a == b + +def getRows(results): + return list(results) + # Result objects contain some strange types specific to the CQL driver, which # normally compare well against normal Python types, but in some cases of nested # types they do not, and require some cleanup: @@ -183,6 +195,22 @@ def assert_rows(result, *expected): assertRows = assert_rows +# Check if results is one of two possible result sets. +# Can be useful in cases where Cassandra and Scylla results are +# expected to be different and we consider that fine. +def assert_rows2(result, expected1, expected2): + allresults = list(result) + assert len(allresults) == len(expected1) or len(allresults) == len(expected2) + same1 = True + for r,e in zip(allresults, expected1): + r = [result_cleanup(col) for col in r] + same1 = same1 and r == e + same2 = True + for r,e in zip(allresults, expected2): + r = [result_cleanup(col) for col in r] + same2 = same2 and r == e + assert same1 or same2 + # To compare two lists of items (each is a dict) without regard for order, # The following function, multiset() converts the list into a multiset # (set with duplicates) where order doesn't matter, so the multisets can diff --git a/test/cql-pytest/cassandra_tests/validation/operations/compact_storage_test.py b/test/cql-pytest/cassandra_tests/validation/operations/compact_storage_test.py new file mode 100644 index 0000000000..7a0a37c1db --- /dev/null +++ b/test/cql-pytest/cassandra_tests/validation/operations/compact_storage_test.py @@ -0,0 +1,4416 @@ +# This file was translated from the original Java test from the Apache +# Cassandra source repository, as of commit a87055d56a33a9b17606f14535f48eb461965b82 +# +# The original Apache Cassandra license: +# +# SPDX-License-Identifier: Apache-2.0 + +from cassandra_tests.porting import * +from uuid import UUID +from cassandra.query import UNSET_VALUE +from cassandra.util import Duration + +compactOption = " WITH COMPACT STORAGE" + +# ALTER ... DROP COMPACT STORAGE was recently dropped (unless a special +# flag is used) by Cassandra, and it was never implemented in Scylla, so +# let's skip its test. +# See issue #3882 +@pytest.mark.skip +def testSparseCompactTableIndex(cql, test_keyspace): + with create_table(cql, test_keyspace, "(key ascii PRIMARY KEY, val ascii) WITH COMPACT STORAGE") as table: + + # Indexes are allowed only on the sparse compact tables + execute(cql, table, "CREATE INDEX ON %s(val)") + for i in range(10): + execute(cql, table, "INSERT INTO %s (key, val) VALUES (?, ?)", str(i), str(i * 10)) + + execute(cql, table, "ALTER TABLE %s DROP COMPACT STORAGE") + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE val = '50'"), + ["5", None, "50", None]) + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE key = '5'"), + ["5", None, "50", None]) + +def testBefore(cql, test_keyspace): + with create_table(cql, test_keyspace, "(key TEXT, column TEXT, value BLOB, PRIMARY KEY (key, column)) WITH COMPACT STORAGE") as table: + largeBytes = bytearray(100000) + execute(cql, table, "INSERT INTO %s (key, column, value) VALUES (?, ?, ?)", "test", "a", largeBytes) + smallBytes = bytearray(10) + execute(cql, table, "INSERT INTO %s (key, column, value) VALUES (?, ?, ?)", "test", "c", smallBytes) + + flush(cql, table) + + assert_rows(execute(cql, table, "SELECT column FROM %s WHERE key = ? AND column IN (?, ?, ?)", "test", "c", "a", "b"), + ["a"], + ["c"]) + +def testStaticCompactTables(cql, test_keyspace): + with create_table(cql, test_keyspace, "(k text PRIMARY KEY, v1 int, v2 text) WITH COMPACT STORAGE") as table: + execute(cql, table, "INSERT INTO %s (k, v1, v2) values (?, ?, ?)", "first", 1, "value1") + execute(cql, table, "INSERT INTO %s (k, v1, v2) values (?, ?, ?)", "second", 2, "value2") + execute(cql, table, "INSERT INTO %s (k, v1, v2) values (?, ?, ?)", "third", 3, "value3") + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE k = ?", "first"), + ["first", 1, "value1"] + ) + + assert_rows(execute(cql, table, "SELECT v2 FROM %s WHERE k = ?", "second"), + ["value2"] + ) + + # Murmur3 order + assert_rows(execute(cql, table, "SELECT * FROM %s"), + ["third", 3, "value3"], + ["second", 2, "value2"], + ["first", 1, "value1"] + ) + +def testCompactStorageUpdateWithNull(cql, test_keyspace): + with create_table(cql, test_keyspace, "(partitionKey int, clustering_1 int, value int, PRIMARY KEY (partitionKey, clustering_1)) WITH COMPACT STORAGE") as table: + execute(cql, table, "INSERT INTO %s (partitionKey, clustering_1, value) VALUES (0, 0, 0)") + execute(cql, table, "INSERT INTO %s (partitionKey, clustering_1, value) VALUES (0, 1, 1)") + + flush(cql, table) + + execute(cql, table, "UPDATE %s SET value = ? WHERE partitionKey = ? AND clustering_1 = ?", None, 0, 0) + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE partitionKey = ? AND (clustering_1) IN ((?), (?))", 0, 0, 1), + [0, 1, 1] + ) + +# Migrated from cql_tests.py:TestCQL.collection_compact_test() +def testCompactCollections(cql, test_keyspace): + tableName = test_keyspace + "." + unique_name() + assert_invalid(cql, test_keyspace, f"CREATE TABLE {tableName} (user ascii PRIMARY KEY, mails list < text >) WITH COMPACT STORAGE;") + +# Check for a table with counters, +# migrated from cql_tests.py:TestCQL.counters_test() +@pytest.mark.xfail(reason="Cassandra 3.10's += syntax not yet supported. Issue #7735") +def testCounters(cql, test_keyspace): + with create_table(cql, test_keyspace, "(userid int, url text, total counter, PRIMARY KEY (userid, url)) WITH COMPACT STORAGE") as table: + execute(cql, table, "UPDATE %s SET total = total + 1 WHERE userid = 1 AND url = 'http://foo.com'") + assert_rows(execute(cql, table, "SELECT total FROM %s WHERE userid = 1 AND url = 'http://foo.com'"), + [1]) + + execute(cql, table, "UPDATE %s SET total = total - 4 WHERE userid = 1 AND url = 'http://foo.com'") + assert_rows(execute(cql, table, "SELECT total FROM %s WHERE userid = 1 AND url = 'http://foo.com'"), + [-3]) + + execute(cql, table, "UPDATE %s SET total = total+1 WHERE userid = 1 AND url = 'http://foo.com'") + assert_rows(execute(cql, table, "SELECT total FROM %s WHERE userid = 1 AND url = 'http://foo.com'"), + [-2]) + + execute(cql, table, "UPDATE %s SET total = total -2 WHERE userid = 1 AND url = 'http://foo.com'") + assert_rows(execute(cql, table, "SELECT total FROM %s WHERE userid = 1 AND url = 'http://foo.com'"), + [-4]) + + # Reproduces #7735: + execute(cql, table, "UPDATE %s SET total += 6 WHERE userid = 1 AND url = 'http://foo.com'") + assert_rows(execute(cql, table, "SELECT total FROM %s WHERE userid = 1 AND url = 'http://foo.com'"), + [2]) + + execute(cql, table, "UPDATE %s SET total -= 1 WHERE userid = 1 AND url = 'http://foo.com'") + assert_rows(execute(cql, table, "SELECT total FROM %s WHERE userid = 1 AND url = 'http://foo.com'"), + [1]) + + execute(cql, table, "UPDATE %s SET total += -2 WHERE userid = 1 AND url = 'http://foo.com'") + assert_rows(execute(cql, table, "SELECT total FROM %s WHERE userid = 1 AND url = 'http://foo.com'"), + [-1]) + + execute(cql, table, "UPDATE %s SET total -= -2 WHERE userid = 1 AND url = 'http://foo.com'") + assert_rows(execute(cql, table, "SELECT total FROM %s WHERE userid = 1 AND url = 'http://foo.com'"), + [1]) + +def testCounterFiltering(cql, test_keyspace): + with create_table(cql, test_keyspace, "(k int PRIMARY KEY, a COUNTER) WITH COMPACT STORAGE") as table: + for i in range(10): + execute(cql, table, "UPDATE %s SET a = a + ? WHERE k = ?", i, i) + + execute(cql, table, "UPDATE %s SET a = a + ? WHERE k = ?", 6, 10) + + # GT + assert_rows_ignoring_order(execute(cql, table, "SELECT * FROM %s WHERE a > ? ALLOW FILTERING", 5), + [6, 6], + [7, 7], + [8, 8], + [9, 9], + [10, 6]) + + # GTE + assert_rows_ignoring_order(execute(cql, table, "SELECT * FROM %s WHERE a >= ? ALLOW FILTERING", 6), + [6, 6], + [7, 7], + [8, 8], + [9, 9], + [10, 6]) + + # LT + assert_rows_ignoring_order(execute(cql, table, "SELECT * FROM %s WHERE a < ? ALLOW FILTERING", 3), + [0, 0], + [1, 1], + [2, 2]) + + # LTE + assert_rows_ignoring_order(execute(cql, table, "SELECT * FROM %s WHERE a <= ? ALLOW FILTERING", 3), + [0, 0], + [1, 1], + [2, 2], + [3, 3]) + + # EQ + assert_rows_ignoring_order(execute(cql, table, "SELECT * FROM %s WHERE a = ? ALLOW FILTERING", 6), + [6, 6], + [10, 6]) + +# Test for the bug of CASSANDRA-11726. +def testCounterAndColumnSelection(cql, test_keyspace): + for compactStorageClause in ["", " WITH COMPACT STORAGE"]: + with create_table(cql, test_keyspace, "(k int PRIMARY KEY, c counter) " + compactStorageClause) as table: + # Flush 2 updates in different sstable so that the following select does a merge, which is what triggers + # the problem from CASSANDRA-11726 + execute(cql, table, "UPDATE %s SET c = c + ? WHERE k = ?", 1, 0) + flush(cql, table) + execute(cql, table, "UPDATE %s SET c = c + ? WHERE k = ?", 1, 0) + flush(cql, table) + # Querying, but not including the counter. Pre-CASSANDRA-11726, this made us query the counter but include + # it's value, which broke at merge (post-CASSANDRA-11726 are special cases to never skip values). + assert_rows(execute(cql, table, "SELECT k FROM %s"), [0]) + +# Check that a counter batch works as intended +def testCounterBatch(cql, test_keyspace): + with create_table(cql, test_keyspace, "(userid int, url text, total counter, PRIMARY KEY (userid, url)) WITH COMPACT STORAGE") as table: + # Ensure we handle updates to the same CQL row in the same partition properly + execute(cql, table, "BEGIN UNLOGGED BATCH " + + "UPDATE %s SET total = total + 1 WHERE userid = 1 AND url = 'http://foo.com'; " + + "UPDATE %s SET total = total + 1 WHERE userid = 1 AND url = 'http://foo.com'; " + + "UPDATE %s SET total = total + 1 WHERE userid = 1 AND url = 'http://foo.com'; " + + "APPLY BATCH; ") + assert_rows(execute(cql, table, "SELECT total FROM %s WHERE userid = 1 AND url = 'http://foo.com'"), + [3]) + + # Ensure we handle different CQL rows in the same partition properly + execute(cql, table, "BEGIN UNLOGGED BATCH " + + "UPDATE %s SET total = total + 1 WHERE userid = 1 AND url = 'http://bar.com'; " + + "UPDATE %s SET total = total + 1 WHERE userid = 1 AND url = 'http://baz.com'; " + + "UPDATE %s SET total = total + 1 WHERE userid = 1 AND url = 'http://bad.com'; " + + "APPLY BATCH; ") + assert_rows(execute(cql, table, "SELECT url, total FROM %s WHERE userid = 1"), + ["http://bad.com", 1], + ["http://bar.com", 1], + ["http://baz.com", 1], + ["http://foo.com", 3]) # from previous batch + + with create_table(cql, test_keyspace, "(userid int, url text, first counter, second counter, third counter, PRIMARY KEY (userid, url))") as table: + # Different counters in the same CQL Row + execute(cql, table, "BEGIN UNLOGGED BATCH " + + "UPDATE %s SET first = first + 1 WHERE userid = 1 AND url = 'http://foo.com'; " + + "UPDATE %s SET first = first + 1 WHERE userid = 1 AND url = 'http://foo.com'; " + + "UPDATE %s SET second = second + 1 WHERE userid = 1 AND url = 'http://foo.com'; " + + "APPLY BATCH; ") + assert_rows(execute(cql, table, "SELECT first, second, third FROM %s WHERE userid = 1 AND url = 'http://foo.com'"), + [2, 1, None]) + + # Different counters in different CQL Rows + execute(cql, table, "BEGIN UNLOGGED BATCH " + + "UPDATE %s SET first = first + 1 WHERE userid = 1 AND url = 'http://bad.com'; " + + "UPDATE %s SET first = first + 1, second = second + 1 WHERE userid = 1 AND url = 'http://bar.com'; " + + "UPDATE %s SET first = first - 1, second = second - 1 WHERE userid = 1 AND url = 'http://bar.com'; " + + "UPDATE %s SET second = second + 1 WHERE userid = 1 AND url = 'http://baz.com'; " + + "APPLY BATCH; ") + assert_rows(execute(cql, table, "SELECT url, first, second, third FROM %s WHERE userid = 1"), + ["http://bad.com", 1, None, None], + ["http://bar.com", 0, 0, None], + ["http://baz.com", None, 1, None], + ["http://foo.com", 2, 1, None]) # from previous batch + + # Different counters in different partitions + execute(cql, table, "BEGIN UNLOGGED BATCH " + + "UPDATE %s SET first = first + 1 WHERE userid = 2 AND url = 'http://bad.com'; " + + "UPDATE %s SET first = first + 1, second = second + 1 WHERE userid = 3 AND url = 'http://bar.com'; " + + "UPDATE %s SET first = first - 1, second = second - 1 WHERE userid = 4 AND url = 'http://bar.com'; " + + "UPDATE %s SET second = second + 1 WHERE userid = 5 AND url = 'http://baz.com'; " + + "APPLY BATCH; ") + assert_rows_ignoring_order(execute(cql, table, "SELECT userid, url, first, second, third FROM %s WHERE userid IN (2, 3, 4, 5)"), + [2, "http://bad.com", 1, None, None], + [3, "http://bar.com", 1, 1, None], + [4, "http://bar.com", -1, -1, None], + [5, "http://baz.com", None, 1, None]) + +# from FrozenCollectionsTest +def testClusteringKeyUsageSet(cql, test_keyspace): + runClusteringKeyUsage(cql, test_keyspace, "set", set(), + {1, 2, 3}, + {4, 5, 6}, + {7, 8, 9}) + +def testClusteringKeyUsageList(cql, test_keyspace): + runClusteringKeyUsage(cql, test_keyspace, "list", + [], + [1, 2, 3], + [4, 5, 6], + [7, 8, 9]) + +def testClusteringKeyUsageMap(cql, test_keyspace): + runClusteringKeyUsage(cql, test_keyspace, "map", + {}, + {1: 10, 2: 20, 3: 30}, + {4: 40, 5: 50, 6: 60}, + {7: 70, 8: 80, 9: 90}) + +def runClusteringKeyUsage(cql, test_keyspace, typ, v1, v2, v3, v4): + with create_table(cql, test_keyspace, f"(a int, b frozen<{typ}>, c int, PRIMARY KEY (a, b)) WITH COMPACT STORAGE") as table: + execute(cql, table, "INSERT INTO %s (a, b, c) VALUES (?, ?, ?)", 0, v1, 1) + execute(cql, table, "INSERT INTO %s (a, b, c) VALUES (?, ?, ?)", 0, v2, 1) + execute(cql, table, "INSERT INTO %s (a, b, c) VALUES (?, ?, ?)", 0, v3, 0) + execute(cql, table, "INSERT INTO %s (a, b, c) VALUES (?, ?, ?)", 0, v4, 0) + + # overwrite with an update + execute(cql, table, "UPDATE %s SET c=? WHERE a=? AND b=?", 0, 0, v1) + execute(cql, table, "UPDATE %s SET c=? WHERE a=? AND b=?", 0, 0, v2) + + assert_rows(execute(cql, table, "SELECT * FROM %s"), + [0, v1, 0], + [0, v2, 0], + [0, v3, 0], + [0, v4, 0] + ) + + assert_rows(execute(cql, table, "SELECT b FROM %s"), + [v1], + [v2], + [v3], + [v4] + ) + + assert_rows(execute(cql, table, "SELECT * FROM %s LIMIT 2"), + [0, v1, 0], + [0, v2, 0] + ) + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE a=? AND b=?", 0, v3), + [0, v3, 0] + ) + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE a=? AND b=?", 0, v1), + [0, v1, 0] + ) + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE a=? AND b IN ?", 0, [v3, v1]), + [0, v1, 0], + [0, v3, 0] + ) + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE a=? AND b > ?", 0, v3), + [0, v4, 0] + ) + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE a=? AND b >= ?", 0, v3), + [0, v3, 0], + [0, v4, 0] + ) + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE a=? AND b < ?", 0, v3), + [0, v1, 0], + [0, v2, 0] + ) + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE a=? AND b <= ?", 0, v3), + [0, v1, 0], + [0, v2, 0], + [0, v3, 0] + ) + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE a=? AND b > ? AND b <= ?", 0, v2, v3), + [0, v3, 0] + ) + + execute(cql, table, "DELETE FROM %s WHERE a=? AND b=?", 0, v1) + execute(cql, table, "DELETE FROM %s WHERE a=? AND b=?", 0, v3) + assert_rows(execute(cql, table, "SELECT * FROM %s"), + [0, v2, 0], + [0, v4, 0] + ) + +def testNestedClusteringKeyUsage(cql, test_keyspace): + with create_table(cql, test_keyspace, f"(a int, b frozen, list>>, c frozen>, d int, PRIMARY KEY (a, b, c)) WITH COMPACT STORAGE") as table: + execute(cql, table, "INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 0, {}, set(), 0) + execute(cql, table, "INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 0, {frozenset(): [1, 2, 3]}, set(), 0) + execute(cql, table, "INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 0, {frozenset({1, 2, 3}): [1, 2, 3]}, {1, 2, 3}, 0) + execute(cql, table, "INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 0, {frozenset({4, 5, 6}): [1, 2, 3]}, {1, 2, 3}, 0) + execute(cql, table, "INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 0, {frozenset({7, 8, 9}): [1, 2, 3]}, {1, 2, 3}, 0) + + assert_rows(execute(cql, table, "SELECT * FROM %s"), + [0, {}, set(), 0], + [0, {frozenset(): [1, 2, 3]}, set(), 0], + [0, {frozenset({1, 2, 3}): [1, 2, 3]}, {1, 2, 3}, 0], + [0, {frozenset({4, 5, 6}): [1, 2, 3]}, {1, 2, 3}, 0], + [0, {frozenset({7, 8, 9}): [1, 2, 3]}, {1, 2, 3}, 0] + ) + + assert_rows(execute(cql, table, "SELECT b FROM %s"), + [{}], + [{frozenset(): [1, 2, 3]}], + [{frozenset({1, 2, 3}): [1, 2, 3]}], + [{frozenset({4, 5, 6}): [1, 2, 3]}], + [{frozenset({7, 8, 9}): [1, 2, 3]}] + ) + + assert_rows(execute(cql, table, "SELECT c FROM %s"), + [set()], + [set()], + [{1, 2, 3}], + [{1, 2, 3}], + [{1, 2, 3}] + ) + + assert_rows(execute(cql, table, "SELECT * FROM %s LIMIT 3"), + [0, {}, set(), 0], + [0, {frozenset(): [1, 2, 3]}, set(), 0], + [0, {frozenset({1, 2, 3}): [1, 2, 3]}, {1, 2, 3}, 0] + ) + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE a=0 ORDER BY b DESC LIMIT 4"), + [0, {frozenset({7, 8, 9}): [1, 2, 3]}, {1, 2, 3}, 0], + [0, {frozenset({4, 5, 6}): [1, 2, 3]}, {1, 2, 3}, 0], + [0, {frozenset({1, 2, 3}): [1, 2, 3]}, {1, 2, 3}, 0], + [0, {frozenset(): [1, 2, 3]}, set(), 0] + ) + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE a=? AND b=?", 0, {}), + [0, {}, set(), 0] + ) + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE a=? AND b=?", 0, {frozenset(): [1, 2, 3]}), + [0, {frozenset(): [1, 2, 3]}, set(), 0] + ) + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE a=? AND b=?", 0, {frozenset({1, 2, 3}): [1, 2, 3]}), + [0, {frozenset({1, 2, 3}): [1, 2, 3]}, {1, 2, 3}, 0] + ) + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE a=? AND b=? AND c=?", 0, {frozenset(): [1, 2, 3]}, set()), + [0, {frozenset(): [1, 2, 3]}, set(), 0] + ) + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE a=? AND (b, c) IN ?", 0, [({frozenset({4, 5, 6}): [1, 2, 3]}, {1, 2, 3}), ({}, set())]), + [0, {}, set(), 0], + [0, {frozenset({4, 5, 6}): [1, 2, 3]}, {1, 2, 3}, 0] + ) + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE a=? AND b > ?", 0, {frozenset({4, 5, 6}): [1, 2, 3]}), + [0, {frozenset({7, 8, 9}): [1, 2, 3]}, {1, 2, 3}, 0] + ) + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE a=? AND b >= ?", 0, {frozenset({4, 5, 6}): [1, 2, 3]}), + [0, {frozenset({4, 5, 6}): [1, 2, 3]}, {1, 2, 3}, 0], + [0, {frozenset({7, 8, 9}): [1, 2, 3]}, {1, 2, 3}, 0] + ) + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE a=? AND b < ?", 0, {frozenset({4, 5, 6}): [1, 2, 3]}), + [0, {}, set(), 0], + [0, {frozenset(): [1, 2, 3]}, set(), 0], + [0, {frozenset({1, 2, 3}): [1, 2, 3]}, {1, 2, 3}, 0] + ) + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE a=? AND b <= ?", 0, {frozenset({4, 5, 6}): [1, 2, 3]}), + [0, {}, set(), 0], + [0, {frozenset(): [1, 2, 3]}, set(), 0], + [0, {frozenset({1, 2, 3}): [1, 2, 3]}, {1, 2, 3}, 0], + [0, {frozenset({4, 5, 6}): [1, 2, 3]}, {1, 2, 3}, 0] + ) + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE a=? AND b > ? AND b <= ?", 0, {frozenset({1, 2, 3}): [1, 2, 3]}, {frozenset({4, 5, 6}): [1, 2, 3]}), + [0, {frozenset({4, 5, 6}): [1, 2, 3]}, {1, 2, 3}, 0] + ) + + execute(cql, table, "DELETE FROM %s WHERE a=? AND b=? AND c=?", 0, {}, set()) + assert_empty(execute(cql, table, "SELECT * FROM %s WHERE a=? AND b=? AND c=?", 0, {}, set())) + + execute(cql, table, "DELETE FROM %s WHERE a=? AND b=? AND c=?", 0, {frozenset(): [1, 2, 3]}, set()) + assert_empty(execute(cql, table, "SELECT * FROM %s WHERE a=? AND b=? AND c=?", 0, {frozenset(): [1, 2, 3]}, set())) + + execute(cql, table, "DELETE FROM %s WHERE a=? AND b=? AND c=?", 0, {frozenset({4, 5, 6}): [1, 2, 3]}, {1, 2, 3}) + assert_empty(execute(cql, table, "SELECT * FROM %s WHERE a=? AND b=? AND c=?", 0, {frozenset({4, 5, 6}): [1, 2, 3]}, {1, 2, 3})) + + assert_rows(execute(cql, table, "SELECT * FROM %s"), + [0, {frozenset({1, 2, 3}): [1, 2, 3]}, {1, 2, 3}, 0], + [0, {frozenset({7, 8, 9}): [1, 2, 3]}, {1, 2, 3}, 0] + ) + +def testNestedClusteringKeyUsageWithReverseOrder(cql, test_keyspace): + with create_table(cql, test_keyspace, f"(a int, b frozen, list>>, c frozen>, d int, PRIMARY KEY (a, b, c)) WITH COMPACT STORAGE AND CLUSTERING ORDER BY (b DESC)") as table: + execute(cql, table, "INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 0, {}, set(), 0) + execute(cql, table, "INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 0, {frozenset(): [1, 2, 3]}, set(), 0) + execute(cql, table, "INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 0, {frozenset({1, 2, 3}): [1, 2, 3]}, {1, 2, 3}, 0) + execute(cql, table, "INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 0, {frozenset({4, 5, 6}): [1, 2, 3]}, {1, 2, 3}, 0) + execute(cql, table, "INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 0, {frozenset({7, 8, 9}): [1, 2, 3]}, {1, 2, 3}, 0) + + assert_rows(execute(cql, table, "SELECT * FROM %s"), + row(0, {frozenset({7, 8, 9}): [1, 2, 3]}, {1, 2, 3}, 0), + row(0, {frozenset({4, 5, 6}): [1, 2, 3]}, {1, 2, 3}, 0), + row(0, {frozenset({1, 2, 3}): [1, 2, 3]}, {1, 2, 3}, 0), + row(0, {frozenset(): [1, 2, 3]}, set(), 0), + row(0, {}, set(), 0) + ) + + assert_rows(execute(cql, table, "SELECT b FROM %s"), + row({frozenset({7, 8, 9}): [1, 2, 3]}), + row({frozenset({4, 5, 6}): [1, 2, 3]}), + row({frozenset({1, 2, 3}): [1, 2, 3]}), + row({frozenset(): [1, 2, 3]}), + row({}) + ) + + assert_rows(execute(cql, table, "SELECT c FROM %s"), + row({1, 2, 3}), + row({1, 2, 3}), + row({1, 2, 3}), + row(set()), + row(set()) + ) + + assert_rows(execute(cql, table, "SELECT * FROM %s LIMIT 3"), + row(0, {frozenset({7, 8, 9}): [1, 2, 3]}, {1, 2, 3}, 0), + row(0, {frozenset({4, 5, 6}): [1, 2, 3]}, {1, 2, 3}, 0), + row(0, {frozenset({1, 2, 3}): [1, 2, 3]}, {1, 2, 3}, 0) + ) + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE a=0 ORDER BY b DESC LIMIT 4"), + row(0, {frozenset({7, 8, 9}): [1, 2, 3]}, {1, 2, 3}, 0), + row(0, {frozenset({4, 5, 6}): [1, 2, 3]}, {1, 2, 3}, 0), + row(0, {frozenset({1, 2, 3}): [1, 2, 3]}, {1, 2, 3}, 0), + row(0, {frozenset(): [1, 2, 3]}, set(), 0) + ) + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE a=? AND b=?", 0, {}), + row(0, {}, set(), 0) + ) + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE a=? AND b=?", 0, {frozenset(): [1, 2, 3]}), + row(0, {frozenset(): [1, 2, 3]}, set(), 0) + ) + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE a=? AND b=?", 0, {frozenset({1, 2, 3}): [1, 2, 3]}), + row(0, {frozenset({1, 2, 3}): [1, 2, 3]}, {1, 2, 3}, 0) + ) + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE a=? AND b=? AND c=?", 0, {frozenset(): [1, 2, 3]}, set()), + row(0, {frozenset(): [1, 2, 3]}, set(), 0) + ) + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE a=? AND (b, c) IN ?", 0, [({frozenset({4, 5, 6}): [1, 2, 3]}, {1, 2, 3}), + ({}, set())]), + row(0, {frozenset({4, 5, 6}): [1, 2, 3]}, {1, 2, 3}, 0), + row(0, {}, set(), 0) + ) + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE a=? AND b > ?", 0, {frozenset({4, 5, 6}): [1, 2, 3]}), + row(0, {frozenset({7, 8, 9}): [1, 2, 3]}, {1, 2, 3}, 0) + ) + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE a=? AND b >= ?", 0, {frozenset({4, 5, 6}): [1, 2, 3]}), + row(0, {frozenset({7, 8, 9}): [1, 2, 3]}, {1, 2, 3}, 0), + row(0, {frozenset({4, 5, 6}): [1, 2, 3]}, {1, 2, 3}, 0) + ) + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE a=? AND b < ?", 0, {frozenset({4, 5, 6}): [1, 2, 3]}), + row(0, {frozenset({1, 2, 3}): [1, 2, 3]}, {1, 2, 3}, 0), + row(0, {frozenset(): [1, 2, 3]}, set(), 0), + row(0, {}, set(), 0) + ) + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE a=? AND b <= ?", 0, {frozenset({4, 5, 6}): [1, 2, 3]}), + row(0, {frozenset({4, 5, 6}): [1, 2, 3]}, {1, 2, 3}, 0), + row(0, {frozenset({1, 2, 3}): [1, 2, 3]}, {1, 2, 3}, 0), + row(0, {frozenset(): [1, 2, 3]}, set(), 0), + row(0, {}, set(), 0) + ) + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE a=? AND b > ? AND b <= ?", 0, {frozenset({1, 2, 3}): [1, 2, 3]}, {frozenset({4, 5, 6}): [1, 2, 3]}), + row(0, {frozenset({4, 5, 6}): [1, 2, 3]}, {1, 2, 3}, 0) + ) + + execute(cql, table, "DELETE FROM %s WHERE a=? AND b=? AND c=?", 0, {}, set()) + assertEmpty(execute(cql, table, "SELECT * FROM %s WHERE a=? AND b=? AND c=?", 0, {}, set())) + + execute(cql, table, "DELETE FROM %s WHERE a=? AND b=? AND c=?", 0, {frozenset(): [1, 2, 3]}, set()) + assertEmpty(execute(cql, table, "SELECT * FROM %s WHERE a=? AND b=? AND c=?", 0, {frozenset(): [1, 2, 3]}, set())) + + execute(cql, table, "DELETE FROM %s WHERE a=? AND b=? AND c=?", 0, {frozenset({4, 5, 6}): [1, 2, 3]}, {1, 2, 3}) + assertEmpty(execute(cql, table, "SELECT * FROM %s WHERE a=? AND b=? AND c=?", 0, {frozenset({4, 5, 6}): [1, 2, 3]}, {1, 2, 3})) + + assert_rows(execute(cql, table, "SELECT * FROM %s"), + row(0, {frozenset({7, 8, 9}): [1, 2, 3]}, {1, 2, 3}, 0), + row(0, {frozenset({1, 2, 3}): [1, 2, 3]}, {1, 2, 3}, 0) + ) + +def testNormalColumnUsage(cql, test_keyspace): + with create_table(cql, test_keyspace, f"(a int PRIMARY KEY, b frozen, list>>, c frozen>)" + compactOption ) as table: + execute(cql, table, "INSERT INTO %s (a, b, c) VALUES (?, ?, ?)", 0, {}, set()) + execute(cql, table, "INSERT INTO %s (a, b, c) VALUES (?, ?, ?)", 1, {frozenset(): [99999, 999999, 99999]}, set()) + execute(cql, table, "INSERT INTO %s (a, b, c) VALUES (?, ?, ?)", 2, {frozenset({1, 2, 3}): [1, 2, 3]}, {1, 2, 3}) + execute(cql, table, "INSERT INTO %s (a, b, c) VALUES (?, ?, ?)", 3, {frozenset({4, 5, 6}): [1, 2, 3]}, {1, 2, 3}) + execute(cql, table, "INSERT INTO %s (a, b, c) VALUES (?, ?, ?)", 4, {frozenset({7, 8, 9}): [1, 2, 3]}, {1, 2, 3}) + + # overwrite with update + execute(cql, table, "UPDATE %s SET b=? WHERE a=?", {frozenset(): [1, 2, 3]}, 1) + + assert_rows_ignoring_order(execute(cql, table, "SELECT * FROM %s"), + [0, {}, set()], + [1, {frozenset(): [1, 2, 3]}, set()], + [2, {frozenset({1, 2, 3}): [1, 2, 3]}, {1, 2, 3}], + [3, {frozenset({4, 5, 6}): [1, 2, 3]}, {1, 2, 3}], + [4, {frozenset({7, 8, 9}): [1, 2, 3]}, {1, 2, 3}] + ) + + assert_rows_ignoring_order(execute(cql, table, "SELECT b FROM %s"), + [{}], + [{frozenset(): [1, 2, 3]}], + [{frozenset({1, 2, 3}): [1, 2, 3]}], + [{frozenset({4, 5, 6}): [1, 2, 3]}], + [{frozenset({7, 8, 9}): [1, 2, 3]}] + ) + + assert_rows_ignoring_order(execute(cql, table, "SELECT c FROM %s"), + [set()], + [set()], + [{1, 2, 3}], + [{1, 2, 3}], + [{1, 2, 3}] + ) + + assert_rows_ignoring_order(execute(cql, table, "SELECT * FROM %s WHERE a=?", 3), + [3, {frozenset({4, 5, 6}): [1, 2, 3]}, {1, 2, 3}] + ) + + execute(cql, table, "UPDATE %s SET b=? WHERE a=?", null, 1) + assert_rows_ignoring_order(execute(cql, table, "SELECT * FROM %s WHERE a=?", 1), + [1, None, set()] + ) + + execute(cql, table, "UPDATE %s SET b=? WHERE a=?", {}, 1) + assert_rows_ignoring_order(execute(cql, table, "SELECT * FROM %s WHERE a=?", 1), + [1, {}, set()] + ) + + execute(cql, table, "UPDATE %s SET c=? WHERE a=?", None, 2) + assert_rows_ignoring_order(execute(cql, table, "SELECT * FROM %s WHERE a=?", 2), + [2, {frozenset({1, 2, 3}): [1, 2, 3]}, None] + ) + + execute(cql, table, "UPDATE %s SET c=? WHERE a=?", set(), 2) + assert_rows_ignoring_order(execute(cql, table, "SELECT * FROM %s WHERE a=?", 2), + [2, {frozenset({1, 2, 3}): [1, 2, 3]}, set()] + ) + + execute(cql, table, "DELETE b FROM %s WHERE a=?", 3) + assert_rows_ignoring_order(execute(cql, table, "SELECT * FROM %s WHERE a=?", 3), + [3, None, {1, 2, 3}] + ) + + execute(cql, table, "DELETE c FROM %s WHERE a=?", 4) + assert_rows_ignoring_order(execute(cql, table, "SELECT * FROM %s WHERE a=?", 4), + [4, {frozenset({7, 8, 9}): [1, 2, 3]}, None] + ) + +TOO_BIG = 1024 * 65 + +# from SecondaryIndexTest +# Reproduces #8627 +@pytest.mark.xfail(reason="issue #8627") +def testCompactTableWithValueOver64k(cql, test_keyspace): + with create_table(cql, test_keyspace, "(a int, b blob, PRIMARY KEY (a)) WITH COMPACT STORAGE") as table: + execute(cql, table, "CREATE INDEX ON %s(b)") + too_big = bytearray([1])*TOO_BIG + failInsert(cql, table, "INSERT INTO %s (a, b) VALUES (0, ?)", too_big) + failInsert(cql, table, "INSERT INTO %s (a, b) VALUES (0, ?) IF NOT EXISTS", too_big) + failInsert(cql, table, "BEGIN BATCH\n" + + "INSERT INTO %s (a, b) VALUES (0, ?);\n" + + "APPLY BATCH", + too_big) + failInsert(cql, table, "BEGIN BATCH\n" + + "INSERT INTO %s (a, b) VALUES (0, ?) IF NOT EXISTS;\n" + + "APPLY BATCH", + too_big) + +def failInsert(cql, table, insertCQL, *args): + with pytest.raises(InvalidRequest): + execute(cql, table, insertCQL, *args) + +# Migrated from cql_tests.py:TestCQL.invalid_clustering_indexing_test() +def testIndexesOnClusteringInvalid(cql, test_keyspace): + with create_table(cql, test_keyspace, "(a int, b int, c int, d int, PRIMARY KEY ((a, b))) WITH COMPACT STORAGE") as table: + assert_invalid(cql, table, "CREATE INDEX ON %s (a)") + assert_invalid(cql, table, "CREATE INDEX ON %s (b)") + with create_table(cql, test_keyspace, "(a int, b int, c int, PRIMARY KEY (a, b)) WITH COMPACT STORAGE") as table: + assert_invalid(cql, table, "CREATE INDEX ON %s (a)") + assert_invalid(cql, table, "CREATE INDEX ON %s (b)") + assert_invalid(cql, table, "CREATE INDEX ON %s (c)") + +def testEmptyRestrictionValueWithSecondaryIndexAndCompactTables(cql, test_keyspace): + with create_table(cql, test_keyspace, "(pk blob, c blob, v blob, PRIMARY KEY ((pk), c)) WITH COMPACT STORAGE") as table: + assertInvalidMessage(cql, table, "COMPACT STORAGE", + "CREATE INDEX on %s(c)") + + with create_table(cql, test_keyspace, "(pk blob PRIMARY KEY, v blob) WITH COMPACT STORAGE") as table: + execute(cql, table, "CREATE INDEX on %s(v)") + execute(cql, table, "INSERT INTO %s (pk, v) VALUES (?, ?)", b"foo123", b"1") + + # Test restrictions on non-primary key value + assertEmpty(execute(cql, table, "SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND v = textAsBlob('');")) + + execute(cql, table, "INSERT INTO %s (pk, v) VALUES (?, ?)", b"foo124", bytearray([])) + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE v = textAsBlob('');"), + row(b"foo124", bytearray([]))) + +def testIndicesOnCompactTable(cql, test_keyspace): + assertInvalidMessage(cql, test_keyspace, "COMPACT STORAGE with composite PRIMARY KEY allows no more than one column not part of the PRIMARY KEY", + "CREATE TABLE " + test_keyspace + "." + unique_name() + " (pk int, c int, v1 int, v2 int, PRIMARY KEY(pk, c)) WITH COMPACT STORAGE") + with create_table(cql, test_keyspace, "(pk blob, c int, v int, PRIMARY KEY (pk, c)) WITH COMPACT STORAGE") as table: + assertInvalidMessage(cql, table, "COMPACT STORAGE", + "CREATE INDEX ON %s(v)") + + with create_table(cql, test_keyspace, "(pk int PRIMARY KEY, v int) WITH COMPACT STORAGE") as table: + execute(cql, table, "CREATE INDEX ON %s(v)") + + execute(cql, table, "INSERT INTO %s (pk, v) VALUES (?, ?)", 1, 1) + execute(cql, table, "INSERT INTO %s (pk, v) VALUES (?, ?)", 2, 1) + execute(cql, table, "INSERT INTO %s (pk, v) VALUES (?, ?)", 3, 3) + + assert_rows(execute(cql, table, "SELECT pk, v FROM %s WHERE v = 1"), + row(1, 1), + row(2, 1)) + + assert_rows(execute(cql, table, "SELECT pk, v FROM %s WHERE v = 3"), + row(3, 3)) + + assertEmpty(execute(cql, table, "SELECT pk, v FROM %s WHERE v = 5")) + + with create_table(cql, test_keyspace, "(pk int PRIMARY KEY, v1 int, v2 int) WITH COMPACT STORAGE") as table: + execute(cql, table, "CREATE INDEX ON %s(v1)") + + execute(cql, table, "INSERT INTO %s (pk, v1, v2) VALUES (?, ?, ?)", 1, 1, 1) + execute(cql, table, "INSERT INTO %s (pk, v1, v2) VALUES (?, ?, ?)", 2, 1, 2) + execute(cql, table, "INSERT INTO %s (pk, v1, v2) VALUES (?, ?, ?)", 3, 3, 3) + + assert_rows(execute(cql, table, "SELECT pk, v2 FROM %s WHERE v1 = 1"), + row(1, 1), + row(2, 2)) + + assert_rows(execute(cql, table, "SELECT pk, v2 FROM %s WHERE v1 = 3"), + row(3, 3)) + + assertEmpty(execute(cql, table, "SELECT pk, v2 FROM %s WHERE v1 = 5")) + +# OverflowTest + +# Test regression from CASSANDRA-5189, +# migrated from cql_tests.py:TestCQL.compact_metadata_test() +def testCompactMetadata(cql, test_keyspace): + with create_table(cql, test_keyspace, "(id int primary key, i int) WITH COMPACT STORAGE") as table: + execute(cql, table, "INSERT INTO %s (id, i) VALUES (1, 2)") + assert_rows(execute(cql, table, "SELECT * FROM %s"), + row(1, 2)) + +def testEmpty(cql, test_keyspace): + # Same test, but for compact + with create_table(cql, test_keyspace, "(k1 int, k2 int, v int, PRIMARY KEY (k1, k2)) WITH COMPACT STORAGE") as table: + # Inserts a few rows to make sure we don 't actually query something + rows = fill(cql, table) + + assertEmpty(execute(cql, table, "SELECT v FROM %s WHERE k1 IN ()")) + assertEmpty(execute(cql, table, "SELECT v FROM %s WHERE k1 = 0 AND k2 IN ()")) + + # Test empty IN() in DELETE + execute(cql, table, "DELETE FROM %s WHERE k1 IN ()") + assertArrayEquals(rows, getRows(execute(cql, table, "SELECT * FROM %s"))) + + # Test empty IN() in UPDATE + execute(cql, table, "UPDATE %s SET v = 3 WHERE k1 IN () AND k2 = 2") + assertArrayEquals(rows, getRows(execute(cql, table, "SELECT * FROM %s"))) + +def fill(cql, table): + for i in range(2): + for j in range(2): + execute(cql, table, "INSERT INTO %s (k1, k2, v) VALUES (?, ?, ?)", i, j, i + j) + return list(execute(cql, table, "SELECT * FROM %s")) + +# AggregationTest +def testFunctionsWithCompactStorage(cql, test_keyspace): + with create_table(cql, test_keyspace, "(a int, b int, c double, primary key (a,b)) WITH COMPACT STORAGE") as table: + execute(cql, table, "INSERT INTO %s (a, b, c) VALUES (1, 1, 11.5)") + execute(cql, table, "INSERT INTO %s (a, b, c) VALUES (1, 2, 9.5)") + execute(cql, table, "INSERT INTO %s (a, b, c) VALUES (1, 3, 9.0)") + + assert_rows(execute(cql, table, "SELECT max(b), min(b), sum(b), avg(b) , max(c), sum(c), avg(c) FROM %s"), + row(3, 1, 6, 2, 11.5, 30.0, 10.0)) + + assert_rows(execute(cql, table, "SELECT COUNT(*) FROM %s"), row(3)) + assert_rows(execute(cql, table, "SELECT COUNT(1) FROM %s"), row(3)) + assert_rows(execute(cql, table, "SELECT COUNT(*) FROM %s WHERE a = 1 AND b > 1"), row(2)) + assert_rows(execute(cql, table, "SELECT COUNT(1) FROM %s WHERE a = 1 AND b > 1"), row(2)) + assert_rows(execute(cql, table, "SELECT max(b), min(b), sum(b), avg(b) , max(c), sum(c), avg(c) FROM %s WHERE a = 1 AND b > 1"), + row(3, 2, 5, 2, 9.5, 18.5, 9.25)) + +# BatchTest +@pytest.mark.xfail(reason="issue #12471") +def testBatchRangeDelete(cql, test_keyspace): + with create_table(cql, test_keyspace, "(partitionKey int, clustering int, value int, primary key (partitionKey, clustering)) WITH COMPACT STORAGE") as table: + value = 0 + for partitionKey in range(4): + for clustering1 in range(5): + execute(cql, table, "INSERT INTO %s (partitionKey, clustering, value) VALUES (?, ?, ?)", + partitionKey, clustering1, value) + value += 1 + execute(cql, table, "BEGIN BATCH " + + "DELETE FROM %s WHERE partitionKey = 1;" + + "DELETE FROM %s WHERE partitionKey = 0 AND clustering >= 4;" + + "DELETE FROM %s WHERE partitionKey = 0 AND clustering <= 0;" + + "DELETE FROM %s WHERE partitionKey = 2 AND clustering >= 0 AND clustering <= 3;" + + "DELETE FROM %s WHERE partitionKey = 2 AND clustering <= 3 AND clustering >= 4;" + + "DELETE FROM %s WHERE partitionKey = 3 AND (clustering) >= (3) AND (clustering) <= (6);" + + "APPLY BATCH;") + + assert_rows(execute(cql, table, "SELECT * FROM %s"), + row(0, 1, 1), + row(0, 2, 2), + row(0, 3, 3), + row(2, 4, 14), + row(3, 0, 15), + row(3, 1, 16), + row(3, 2, 17)) + +# CreateTest +# Creation and basic operations on a static table with compact storage, +# migrated from cql_tests.py:TestCQL.noncomposite_static_cf_test() +def testDenseStaticTable(cql, test_keyspace): + with create_table(cql, test_keyspace, "(userid uuid PRIMARY KEY, firstname text, lastname text, age int) WITH COMPACT STORAGE") as table: + id1 = UUID("550e8400-e29b-41d4-a716-446655440000") + id2 = UUID("f47ac10b-58cc-4372-a567-0e02b2c3d479") + execute(cql, table, "INSERT INTO %s (userid, firstname, lastname, age) VALUES (?, ?, ?, ?)", id1, "Frodo", "Baggins", 32) + execute(cql, table, "UPDATE %s SET firstname = ?, lastname = ?, age = ? WHERE userid = ?", "Samwise", "Gamgee", 33, id2) + + assert_rows(execute(cql, table, "SELECT firstname, lastname FROM %s WHERE userid = ?", id1), + row("Frodo", "Baggins")) + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE userid = ?", id1), + row(id1, 32, "Frodo", "Baggins")) + + assert_rows(execute(cql, table, "SELECT * FROM %s"), + row(id2, 33, "Samwise", "Gamgee"), + row(id1, 32, "Frodo", "Baggins") + ) + + batch = "BEGIN BATCH INSERT INTO %s (userid, age) VALUES (?, ?) UPDATE %s SET age = ? WHERE userid = ? DELETE firstname, lastname FROM %s WHERE userid = ? DELETE firstname, lastname FROM %s WHERE userid = ? APPLY BATCH" + + execute(cql, table, batch, id1, 36, 37, id2, id1, id2) + + assert_rows(execute(cql, table, "SELECT * FROM %s"), + row(id2, 37, None, None), + row(id1, 36, None, None)) + +# Creation and basic operations on a non-composite table with compact storage, +# migrated from cql_tests.py:TestCQL.dynamic_cf_test() +def testDenseNonCompositeTable(cql, test_keyspace): + with create_table(cql, test_keyspace, "(userid uuid, url text, time bigint, PRIMARY KEY (userid, url)) WITH COMPACT STORAGE") as table: + id1 = UUID("550e8400-e29b-41d4-a716-446655440000") + id2 = UUID("f47ac10b-58cc-4372-a567-0e02b2c3d479") + id3 = UUID("810e8500-e29b-41d4-a716-446655440000") + + execute(cql, table, "INSERT INTO %s (userid, url, time) VALUES (?, ?, ?)", id1, "http://foo.bar", 42) + execute(cql, table, "INSERT INTO %s (userid, url, time) VALUES (?, ?, ?)", id1, "http://foo-2.bar", 24) + execute(cql, table, "INSERT INTO %s (userid, url, time) VALUES (?, ?, ?)", id1, "http://bar.bar", 128) + execute(cql, table, "UPDATE %s SET time = 24 WHERE userid = ? and url = 'http://bar.foo'", id2) + execute(cql, table, "UPDATE %s SET time = 12 WHERE userid IN (?, ?) and url = 'http://foo-3'", id2, id1) + + assert_rows(execute(cql, table, "SELECT url, time FROM %s WHERE userid = ?", id1), + row("http://bar.bar", 128), + row("http://foo-2.bar", 24), + row("http://foo-3", 12), + row("http://foo.bar", 42)) + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE userid = ?", id2), + row(id2, "http://bar.foo", 24), + row(id2, "http://foo-3", 12)) + + assert_rows(execute(cql, table, "SELECT time FROM %s"), + row(24), # id2 + row(12), + row(128), # id1 + row(24), + row(12), + row(42) + ) + + # Check we don't allow empty values for url since this is the full underlying cell name (CASSANDRA-6152) + assert_invalid(cql, table, "INSERT INTO %s (userid, url, time) VALUES (?, '', 42)", id3) + +# Creation and basic operations on a composite table with compact storage, +# migrated from cql_tests.py:TestCQL.dense_cf_test() +def testDenseCompositeTable(cql, test_keyspace): + with create_table(cql, test_keyspace, "(userid uuid, ip text, port int, time bigint, PRIMARY KEY (userid, ip, port)) WITH COMPACT STORAGE") as table: + id1 = UUID("550e8400-e29b-41d4-a716-446655440000") + id2 = UUID("f47ac10b-58cc-4372-a567-0e02b2c3d479") + + execute(cql, table, "INSERT INTO %s (userid, ip, port, time) VALUES (?, '192.168.0.1', 80, 42)", id1) + execute(cql, table, "INSERT INTO %s (userid, ip, port, time) VALUES (?, '192.168.0.2', 80, 24)", id1) + execute(cql, table, "INSERT INTO %s (userid, ip, port, time) VALUES (?, '192.168.0.2', 90, 42)", id1) + execute(cql, table, "UPDATE %s SET time = 24 WHERE userid = ? AND ip = '192.168.0.2' AND port = 80", id2) + + # we don't have to include all of the clustering columns (see CASSANDRA-7990) + execute(cql, table, "INSERT INTO %s (userid, ip, time) VALUES (?, '192.168.0.3', 42)", id2) + execute(cql, table, "UPDATE %s SET time = 42 WHERE userid = ? AND ip = '192.168.0.4'", id2) + + assert_rows(execute(cql, table, "SELECT ip, port, time FROM %s WHERE userid = ?", id1), + row("192.168.0.1", 80, 42), + row("192.168.0.2", 80, 24), + row("192.168.0.2", 90, 42)) + + assert_rows(execute(cql, table, "SELECT ip, port, time FROM %s WHERE userid = ? and ip >= '192.168.0.2'", id1), + row("192.168.0.2", 80, 24), + row("192.168.0.2", 90, 42)) + + assert_rows(execute(cql, table, "SELECT ip, port, time FROM %s WHERE userid = ? and ip = '192.168.0.2'", id1), + row("192.168.0.2", 80, 24), + row("192.168.0.2", 90, 42)) + + assertEmpty(execute(cql, table, "SELECT ip, port, time FROM %s WHERE userid = ? and ip > '192.168.0.2'", id1)) + + assert_rows(execute(cql, table, "SELECT ip, port, time FROM %s WHERE userid = ? AND ip = '192.168.0.3'", id2), + row("192.168.0.3", None, 42)) + + assert_rows(execute(cql, table, "SELECT ip, port, time FROM %s WHERE userid = ? AND ip = '192.168.0.4'", id2), + row("192.168.0.4", None, 42)) + + execute(cql, table, "DELETE time FROM %s WHERE userid = ? AND ip = '192.168.0.2' AND port = 80", id1) + + assertRowCount(execute(cql, table, "SELECT * FROM %s WHERE userid = ?", id1), 2) + + execute(cql, table, "DELETE FROM %s WHERE userid = ?", id1) + assertEmpty(execute(cql, table, "SELECT * FROM %s WHERE userid = ?", id1)) + + execute(cql, table, "DELETE FROM %s WHERE userid = ? AND ip = '192.168.0.3'", id2) + assertEmpty(execute(cql, table, "SELECT * FROM %s WHERE userid = ? AND ip = '192.168.0.3'", id2)) + +def testCreateIndexOnCompactTableWithClusteringColumns(cql, test_keyspace): + with create_table(cql, test_keyspace, "(a int, b int, c int, PRIMARY KEY (a, b)) WITH COMPACT STORAGE") as table: + assertInvalidMessage(cql, table, "COMPACT STORAGE", + "CREATE INDEX ON %s (a);") + + assertInvalidMessage(cql, table, "COMPACT STORAGE", + "CREATE INDEX ON %s (b);") + + assertInvalidMessage(cql, table, "COMPACT STORAGE", + "CREATE INDEX ON %s (c);") + +def testCreateIndexOnCompactTableWithoutClusteringColumns(cql, test_keyspace): + with create_table(cql, test_keyspace, "(a int PRIMARY KEY, b int) WITH COMPACT STORAGE") as table: + assertInvalidMessage(cql, table, "Secondary indexes are not supported on PRIMARY KEY columns in COMPACT STORAGE tables", + "CREATE INDEX ON %s (a);") + + execute(cql, table, "CREATE INDEX ON %s (b);") + + execute(cql, table, "INSERT INTO %s (a, b) values (1, 1)") + execute(cql, table, "INSERT INTO %s (a, b) values (2, 4)") + execute(cql, table, "INSERT INTO %s (a, b) values (3, 6)") + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE b = ?", 4), row(2, 4)) + +# DeleteTest + +@pytest.mark.xfail(reason="issue #12474") +@pytest.mark.parametrize("forceFlush", [False, True]) +def testDeleteWithNoClusteringColumns(cql, test_keyspace, forceFlush): + with create_table(cql, test_keyspace, "(partitionkey int PRIMARY KEY, value int) WITH COMPACT STORAGE") as table: + execute(cql, table, "INSERT INTO %s (partitionKey, value) VALUES (0, 0)") + execute(cql, table, "INSERT INTO %s (partitionKey, value) VALUES (1, 1)") + execute(cql, table, "INSERT INTO %s (partitionKey, value) VALUES (2, 2)") + execute(cql, table, "INSERT INTO %s (partitionKey, value) VALUES (3, 3)") + if forceFlush: + flush(cql, table) + + execute(cql, table, "DELETE value FROM %s WHERE partitionKey = ?", 0) + if forceFlush: + flush(cql, table) + + assertEmpty(execute(cql, table, "SELECT * FROM %s WHERE partitionKey = ?", 0)) + + execute(cql, table, "DELETE FROM %s WHERE partitionKey IN (?, ?)", 0, 1) + if forceFlush: + flush(cql, table) + assert_rows(execute(cql, table, "SELECT * FROM %s"), + row(2, 2), + row(3, 3)) + + # test invalid queries + + # token function + assertInvalidMessage(cql, table, "The token function cannot be used in WHERE clauses for", + "DELETE FROM %s WHERE token(partitionKey) = token(?)", 0) + + # multiple time same primary key element in WHERE clause + # As explained in #12472, Scylla allows this case that Cassandra + # forbids, so the check is commented out: + #assertInvalidMessage(cql, table, "partitionkey cannot be restricted by more than one relation if it includes an Equal", + # "DELETE FROM %s WHERE partitionKey = ? AND partitionKey = ?", 0, 1) + + # Undefined column names + assertInvalidMessage(cql, table, "unknown", + "DELETE unknown FROM %s WHERE partitionKey = ?", 0) + + assertInvalidMessage(cql, table, "partitionkey1", + "DELETE FROM %s WHERE partitionKey1 = ?", 0) + + # Invalid operator in the where clause + assertInvalidMessage(cql, table, "Only EQ and IN relation are supported on the partition key", + "DELETE FROM %s WHERE partitionKey > ? ", 0) + + assertInvalidMessage(cql, table, "Cannot use CONTAINS on non-collection column", + "DELETE FROM %s WHERE partitionKey CONTAINS ?", 0) + + # Non primary key in the where clause + # Reproduces #12474: + assertInvalidMessage(cql, table, "Non PRIMARY KEY columns found in where clause: value", + "DELETE FROM %s WHERE partitionKey = ? AND value = ?", 0, 1) + + +@pytest.mark.parametrize("forceFlush", [False, True]) +def testDeleteWithOneClusteringColumns(cql, test_keyspace, forceFlush): + with create_table(cql, test_keyspace, "(partitionKey int, clustering int, value int, PRIMARY KEY (partitionKey, clustering)) WITH COMPACT STORAGE") as table: + execute(cql, table, "INSERT INTO %s (partitionKey, clustering, value) VALUES (0, 0, 0)") + execute(cql, table, "INSERT INTO %s (partitionKey, clustering, value) VALUES (0, 1, 1)") + execute(cql, table, "INSERT INTO %s (partitionKey, clustering, value) VALUES (0, 2, 2)") + execute(cql, table, "INSERT INTO %s (partitionKey, clustering, value) VALUES (0, 3, 3)") + execute(cql, table, "INSERT INTO %s (partitionKey, clustering, value) VALUES (0, 4, 4)") + execute(cql, table, "INSERT INTO %s (partitionKey, clustering, value) VALUES (0, 5, 5)") + execute(cql, table, "INSERT INTO %s (partitionKey, clustering, value) VALUES (1, 0, 6)") + if forceFlush: + flush(cql, table) + + execute(cql, table, "DELETE value FROM %s WHERE partitionKey = ? AND clustering = ?", 0, 1) + if forceFlush: + flush(cql, table) + + assertEmpty(execute(cql, table, "SELECT * FROM %s WHERE partitionKey = ? AND clustering = ?", 0, 1)) + + execute(cql, table, "DELETE FROM %s WHERE partitionKey = ? AND clustering = ?", 0, 1) + if forceFlush: + flush(cql, table) + assertEmpty(execute(cql, table, "SELECT value FROM %s WHERE partitionKey = ? AND clustering = ?", 0, 1)) + + execute(cql, table, "DELETE FROM %s WHERE partitionKey IN (?, ?) AND clustering = ?", 0, 1, 0) + if forceFlush: + flush(cql, table) + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE partitionKey IN (?, ?)", 0, 1), + row(0, 2, 2), + row(0, 3, 3), + row(0, 4, 4), + row(0, 5, 5)) + + execute(cql, table, "DELETE FROM %s WHERE partitionKey = ? AND (clustering) IN ((?), (?))", 0, 4, 5) + if forceFlush: + flush(cql, table) + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE partitionKey IN (?, ?)", 0, 1), + row(0, 2, 2), + row(0, 3, 3)) + + # test invalid queries + + # missing primary key element + assertInvalidMessage(cql, table, "partitionkey", + "DELETE FROM %s WHERE clustering = ?", 1) + + # token function + assertInvalidMessage(cql, table, "The token function cannot be used in WHERE clauses for", + "DELETE FROM %s WHERE token(partitionKey) = token(?) AND clustering = ? ", 0, 1) + + # multiple time same primary key element in WHERE clause + # As explained in #12472, Scylla allows this case that Cassandra + # forbids, so the check is commented out: + #assertInvalidMessage(cql, table, "clustering cannot be restricted by more than one relation if it includes an Equal", + # "DELETE FROM %s WHERE partitionKey = ? AND clustering = ? AND clustering = ?", 0, 1, 1) + + # Undefined column names + assertInvalidMessage(cql, table, "value1", + "DELETE value1 FROM %s WHERE partitionKey = ? AND clustering = ?", 0, 1) + + assertInvalidMessage(cql, table, "partitionkey1", + "DELETE FROM %s WHERE partitionKey1 = ? AND clustering = ?", 0, 1) + + assertInvalidMessage(cql, table, "clustering_3", + "DELETE FROM %s WHERE partitionKey = ? AND clustering_3 = ?", 0, 1) + + # Invalid operator in the where clause + assertInvalidMessage(cql, table, "Only EQ and IN relation are supported on the partition key", + "DELETE FROM %s WHERE partitionKey > ? AND clustering = ?", 0, 1) + + assertInvalidMessage(cql, table, "Cannot use CONTAINS on non-collection column", + "DELETE FROM %s WHERE partitionKey CONTAINS ? AND clustering = ?", 0, 1) + + # Non primary key in the where clause + assertInvalidMessage(cql, table, "value", + "DELETE FROM %s WHERE partitionKey = ? AND clustering = ? AND value = ?", 0, 1, 3) + +@pytest.mark.xfail(reason="issue #4244") +@pytest.mark.parametrize("forceFlush", [False, True]) +def testDeleteWithTwoClusteringColumns(cql, test_keyspace, forceFlush): + with create_table(cql, test_keyspace, "(partitionKey int, clustering_1 int, clustering_2 int, value int, PRIMARY KEY (partitionKey, clustering_1, clustering_2)) WITH COMPACT STORAGE") as table: + + execute(cql, table, "INSERT INTO %s (partitionKey, clustering_1, clustering_2, value) VALUES (0, 0, 0, 0)") + execute(cql, table, "INSERT INTO %s (partitionKey, clustering_1, clustering_2, value) VALUES (0, 0, 1, 1)") + execute(cql, table, "INSERT INTO %s (partitionKey, clustering_1, clustering_2, value) VALUES (0, 0, 2, 2)") + execute(cql, table, "INSERT INTO %s (partitionKey, clustering_1, clustering_2, value) VALUES (0, 0, 3, 3)") + execute(cql, table, "INSERT INTO %s (partitionKey, clustering_1, clustering_2, value) VALUES (0, 1, 1, 4)") + execute(cql, table, "INSERT INTO %s (partitionKey, clustering_1, clustering_2, value) VALUES (0, 1, 2, 5)") + execute(cql, table, "INSERT INTO %s (partitionKey, clustering_1, clustering_2, value) VALUES (1, 0, 0, 6)") + if forceFlush: + flush(cql, table) + + execute(cql, table, "DELETE value FROM %s WHERE partitionKey = ? AND clustering_1 = ? AND clustering_2 = ?", 0, 1, 1) + if forceFlush: + flush(cql, table) + + assertEmpty(execute(cql, table, "SELECT * FROM %s WHERE partitionKey = ? AND clustering_1 = ? AND clustering_2 = ?", + 0, 1, 1)) + + execute(cql, table, "DELETE FROM %s WHERE partitionKey = ? AND (clustering_1, clustering_2) = (?, ?)", 0, 1, 1) + if forceFlush: + flush(cql, table) + assertEmpty(execute(cql, table, "SELECT value FROM %s WHERE partitionKey = ? AND clustering_1 = ? AND clustering_2 = ?", + 0, 1, 1)) + + execute(cql, table, "DELETE FROM %s WHERE partitionKey IN (?, ?) AND clustering_1 = ? AND clustering_2 = ?", 0, 1, 0, 0) + if forceFlush: + flush(cql, table) + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE partitionKey IN (?, ?)", 0, 1), + row(0, 0, 1, 1), + row(0, 0, 2, 2), + row(0, 0, 3, 3), + row(0, 1, 2, 5)) + + rows = [row(0, 0, 1, 1), row(0, 1, 2, 5)] + + execute(cql, table, "DELETE value FROM %s WHERE partitionKey = ? AND clustering_1 = ? AND clustering_2 IN (?, ?)", 0, 0, 2, 3) + if forceFlush: + flush(cql, table) + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE partitionKey IN (?, ?)", 0, 1), *rows) + + rows = [row(0, 0, 1, 1)] + + execute(cql, table, "DELETE FROM %s WHERE partitionKey = ? AND (clustering_1, clustering_2) IN ((?, ?), (?, ?))", 0, 0, 2, 1, 2) + if forceFlush: + flush(cql, table) + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE partitionKey IN (?, ?)", 0, 1), *rows) + + # Reproduces #4244: + execute(cql, table, "DELETE FROM %s WHERE partitionKey = ? AND (clustering_1) IN ((?), (?)) AND clustering_2 = ?", 0, 0, 2, 3) + if forceFlush: + flush(cql, table) + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE partitionKey IN (?, ?)", 0, 1), + row(0, 0, 1, 1)) + + # test invalid queries + + # missing primary key element + assertInvalidMessage(cql, table, "partitionkey", + "DELETE FROM %s WHERE clustering_1 = ? AND clustering_2 = ?", 1, 1) + + assertInvalidMessage(cql, table, "PRIMARY KEY column \"clustering_2\" cannot be restricted as preceding column \"clustering_1\" is not restricted", + "DELETE FROM %s WHERE partitionKey = ? AND clustering_2 = ?", 0, 1) + + # token function + assertInvalidMessage(cql, table, "The token function cannot be used in WHERE clauses for", + "DELETE FROM %s WHERE token(partitionKey) = token(?) AND clustering_1 = ? AND clustering_2 = ?", 0, 1, 1) + + # multiple time same primary key element in WHERE clause + # As explained in #12472, Scylla allows this case that Cassandra + # forbids, so the check is commented out: + #assertInvalidMessage(cql, table, "clustering_1 cannot be restricted by more than one relation if it includes an Equal", + # "DELETE FROM %s WHERE partitionKey = ? AND clustering_1 = ? AND clustering_2 = ? AND clustering_1 = ?", 0, 1, 1, 1) + + # Undefined column names + assertInvalidMessage(cql, table, "value1", + "DELETE value1 FROM %s WHERE partitionKey = ? AND clustering_1 = ? AND clustering_2 = ?", 0, 1, 1) + + assertInvalidMessage(cql, table, "partitionkey1", + "DELETE FROM %s WHERE partitionKey1 = ? AND clustering_1 = ? AND clustering_2 = ?", 0, 1, 1) + + assertInvalidMessage(cql, table, "clustering_3", + "DELETE FROM %s WHERE partitionKey = ? AND clustering_1 = ? AND clustering_3 = ?", 0, 1, 1) + + # Invalid operator in the where clause + assertInvalidMessage(cql, table, "Only EQ and IN relation are supported on the partition key", + "DELETE FROM %s WHERE partitionKey > ? AND clustering_1 = ? AND clustering_2 = ?", 0, 1, 1) + + assertInvalidMessage(cql, table, "Cannot use CONTAINS on non-collection column", + "DELETE FROM %s WHERE partitionKey CONTAINS ? AND clustering_1 = ? AND clustering_2 = ?", 0, 1, 1) + + # Non primary key in the where clause + assertInvalidMessage(cql, table, "value", + "DELETE FROM %s WHERE partitionKey = ? AND clustering_1 = ? AND clustering_2 = ? AND value = ?", 0, 1, 1, 3) + +# InsertTest +@pytest.mark.parametrize("forceFlush", [False, True]) +def testInsertWithCompactFormat(cql, test_keyspace, forceFlush): + with create_table(cql, test_keyspace, "(partitionKey int, clustering int, value int, PRIMARY KEY (partitionKey, clustering)) WITH COMPACT STORAGE") as table: + execute(cql, table, "INSERT INTO %s (partitionKey, clustering, value) VALUES (0, 0, 0)") + execute(cql, table, "INSERT INTO %s (partitionKey, clustering, value) VALUES (0, 1, 1)") + if forceFlush: + flush(cql, table) + + assert_rows(execute(cql, table, "SELECT * FROM %s"), + row(0, 0, 0), + row(0, 1, 1)) + + # Invalid Null values for the clustering key or the regular column + assertInvalidMessage(cql, table, "clustering", + "INSERT INTO %s (partitionKey, value) VALUES (0, 0)") + assertInvalidMessage(cql, table, "Column value is mandatory for this COMPACT STORAGE table", + "INSERT INTO %s (partitionKey, clustering) VALUES (0, 0)") + + # Missing primary key columns + assertInvalidMessage(cql, table, "partitionkey", + "INSERT INTO %s (clustering, value) VALUES (0, 1)") + + # multiple time the same value + assertInvalidMessageRE(cql, table, "duplicates|Multiple", + "INSERT INTO %s (partitionKey, clustering, value, value) VALUES (0, 0, 2, 2)") + + # multiple time same primary key element in WHERE clause + assertInvalidMessageRE(cql, table, "duplicates|Multiple", + "INSERT INTO %s (partitionKey, clustering, clustering, value) VALUES (0, 0, 0, 2)") + + # Undefined column names + assertInvalidMessage(cql, table, "clusteringx", + "INSERT INTO %s (partitionKey, clusteringx, value) VALUES (0, 0, 2)") + + assertInvalidMessage(cql, table, "valuex", + "INSERT INTO %s (partitionKey, clustering, valuex) VALUES (0, 0, 2)") + +@pytest.mark.parametrize("forceFlush", [False, True]) +def testInsertWithCompactStorageAndTwoClusteringColumns(cql, test_keyspace, forceFlush): + with create_table(cql, test_keyspace, "(partitionKey int, clustering_1 int, clustering_2 int, value int, PRIMARY KEY (partitionKey, clustering_1, clustering_2)) WITH COMPACT STORAGE") as table: + execute(cql, table, "INSERT INTO %s (partitionKey, clustering_1, value) VALUES (0, 0, 0)") + execute(cql, table, "INSERT INTO %s (partitionKey, clustering_1, clustering_2, value) VALUES (0, 0, 0, 0)") + execute(cql, table, "INSERT INTO %s (partitionKey, clustering_1, clustering_2, value) VALUES (0, 0, 1, 1)") + if forceFlush: + flush(cql, table) + + assert_rows(execute(cql, table, "SELECT * FROM %s"), + row(0, 0, null, 0), + row(0, 0, 0, 0), + row(0, 0, 1, 1)) + + # Invalid Null values for the clustering key or the regular column + assertInvalidMessage(cql, table, "PRIMARY KEY column \"clustering_2\" cannot be restricted as preceding column \"clustering_1\" is not restricted", + "INSERT INTO %s (partitionKey, clustering_2, value) VALUES (0, 0, 0)") + assertInvalidMessage(cql, table, "Column value is mandatory for this COMPACT STORAGE table", + "INSERT INTO %s (partitionKey, clustering_1, clustering_2) VALUES (0, 0, 0)") + + # Missing primary key columns + assertInvalidMessage(cql, table, "partitionkey", + "INSERT INTO %s (clustering_1, clustering_2, value) VALUES (0, 0, 1)") + assertInvalidMessage(cql, table, "PRIMARY KEY column \"clustering_2\" cannot be restricted as preceding column \"clustering_1\" is not restricted", + "INSERT INTO %s (partitionKey, clustering_2, value) VALUES (0, 0, 2)") + + # multiple time the same value + assertInvalidMessageRE(cql, table, "duplicates|Multiple", + "INSERT INTO %s (partitionKey, clustering_1, value, clustering_2, value) VALUES (0, 0, 2, 0, 2)") + + # multiple time same primary key element in WHERE clause + assertInvalidMessageRE(cql, table, "duplicates|Multiple", + "INSERT INTO %s (partitionKey, clustering_1, clustering_1, clustering_2, value) VALUES (0, 0, 0, 0, 2)") + + # Undefined column names + assertInvalidMessage(cql, table, "clustering_1x", + "INSERT INTO %s (partitionKey, clustering_1x, clustering_2, value) VALUES (0, 0, 0, 2)") + + assertInvalidMessage(cql, table, "valuex", + "INSERT INTO %s (partitionKey, clustering_1, clustering_2, valuex) VALUES (0, 0, 0, 2)") + +# InsertUpdateIfConditionTest +# Test for CAS with compact storage table, and CASSANDRA-6813 in particular, +# migrated from cql_tests.py:TestCQL.cas_and_compact_test() +def testCompactStorage(cql, test_keyspace): + with create_table(cql, test_keyspace, "(partition text, key text, owner text, PRIMARY KEY (partition, key)) WITH COMPACT STORAGE") as table: + execute(cql, table, "INSERT INTO %s (partition, key, owner) VALUES ('a', 'b', null)") + # As explained in docs/kb/lwt-differences.rst, Scylla deliberately + # differs from Cassandra in that it always returns the tested column's + # value, even in True (successful) conditional writes. + assert_rows2(execute(cql, table, "UPDATE %s SET owner='z' WHERE partition='a' AND key='b' IF owner=null"), [row(True)], [row(True, None)]) + + assert_rows(execute(cql, table, "UPDATE %s SET owner='b' WHERE partition='a' AND key='b' IF owner='a'"), row(False, "z")) + assert_rows2(execute(cql, table, "UPDATE %s SET owner='b' WHERE partition='a' AND key='b' IF owner='z'"), [row(True)], [row(True, 'z')]) + + assert_rows2(execute(cql, table, "INSERT INTO %s (partition, key, owner) VALUES ('a', 'c', 'x') IF NOT EXISTS"), [row(True)], [row(True,None,None,None)]) + +# SelectGroupByTest +@pytest.mark.xfail(reason="issue #4244, #5361, #5362, #5363, #12477, #12479") +def testGroupByWithoutPaging(cql, test_keyspace): + with create_table(cql, test_keyspace, "(a int, b int, c int, d int, e int, PRIMARY KEY (a, b, c, d)) WITH COMPACT STORAGE") as table: + execute(cql, table, "INSERT INTO %s (a, b, c, d, e) VALUES (1, 2, 1, 3, 6)") + execute(cql, table, "INSERT INTO %s (a, b, c, d, e) VALUES (1, 2, 2, 6, 12)") + execute(cql, table, "INSERT INTO %s (a, b, c, d, e) VALUES (1, 3, 2, 12, 24)") + execute(cql, table, "INSERT INTO %s (a, b, c, d, e) VALUES (1, 4, 2, 12, 24)") + execute(cql, table, "INSERT INTO %s (a, b, c, d, e) VALUES (1, 4, 2, 6, 12)") + execute(cql, table, "INSERT INTO %s (a, b, c, d, e) VALUES (2, 2, 3, 3, 6)") + execute(cql, table, "INSERT INTO %s (a, b, c, d, e) VALUES (2, 4, 3, 6, 12)") + execute(cql, table, "INSERT INTO %s (a, b, c, d, e) VALUES (3, 3, 2, 12, 24)") + execute(cql, table, "INSERT INTO %s (a, b, c, d, e) VALUES (4, 8, 2, 12, 24)") + + # Makes sure that we have some tombstones + execute(cql, table, "DELETE FROM %s WHERE a = 1 AND b = 3 AND c = 2 AND d = 12") + execute(cql, table, "DELETE FROM %s WHERE a = 3") + + # Range queries + assert_rows(execute(cql, table, "SELECT a, b, e, count(b), max(e) FROM %s GROUP BY a"), + row(1, 2, 6, 4, 24), + row(2, 2, 6, 2, 12), + row(4, 8, 24, 1, 24)) + + assert_rows(execute(cql, table, "SELECT a, b, e, count(b), max(e) FROM %s GROUP BY a, b"), + row(1, 2, 6, 2, 12), + row(1, 4, 12, 2, 24), + row(2, 2, 6, 1, 6), + row(2, 4, 12, 1, 12), + row(4, 8, 24, 1, 24)) + + assert_rows(execute(cql, table, "SELECT a, b, e, count(b), max(e) FROM %s WHERE b = 2 GROUP BY a, b ALLOW FILTERING"), + row(1, 2, 6, 2, 12), + row(2, 2, 6, 1, 6)) + + # Reproduces #12477: + assertEmpty(execute(cql, table, "SELECT a, b, e, count(b), max(e) FROM %s WHERE b IN () GROUP BY a, b ALLOW FILTERING")) + + # Range queries without aggregates + assert_rows(execute(cql, table, "SELECT a, b, c, d FROM %s GROUP BY a, b, c"), + row(1, 2, 1, 3), + row(1, 2, 2, 6), + row(1, 4, 2, 6), + row(2, 2, 3, 3), + row(2, 4, 3, 6), + row(4, 8, 2, 12)) + + assert_rows(execute(cql, table, "SELECT a, b, c, d FROM %s GROUP BY a, b"), + row(1, 2, 1, 3), + row(1, 4, 2, 6), + row(2, 2, 3, 3), + row(2, 4, 3, 6), + row(4, 8, 2, 12)) + + # Range queries with wildcard + assert_rows(execute(cql, table, "SELECT * FROM %s GROUP BY a, b, c"), + row(1, 2, 1, 3, 6), + row(1, 2, 2, 6, 12), + row(1, 4, 2, 6, 12), + row(2, 2, 3, 3, 6), + row(2, 4, 3, 6, 12), + row(4, 8, 2, 12, 24)) + + assert_rows(execute(cql, table, "SELECT * FROM %s GROUP BY a, b"), + row(1, 2, 1, 3, 6), + row(1, 4, 2, 6, 12), + row(2, 2, 3, 3, 6), + row(2, 4, 3, 6, 12), + row(4, 8, 2, 12, 24)) + + # Range query with LIMIT + # Reproduces #5361: + assert_rows(execute(cql, table, "SELECT a, b, e, count(b), max(e) FROM %s GROUP BY a, b LIMIT 2"), + row(1, 2, 6, 2, 12), + row(1, 4, 12, 2, 24)) + + # Range queries with PER PARTITION LIMIT + # Reproduces #5363: + assert_rows(execute(cql, table, "SELECT a, b, e, count(b), max(e) FROM %s GROUP BY a, b PER PARTITION LIMIT 1"), + row(1, 2, 6, 2, 12), + row(2, 2, 6, 1, 6), + row(4, 8, 24, 1, 24)) + + assert_rows(execute(cql, table, "SELECT a, b, e, count(b), max(e) FROM %s GROUP BY a PER PARTITION LIMIT 2"), + row(1, 2, 6, 4, 24), + row(2, 2, 6, 2, 12), + row(4, 8, 24, 1, 24)) + + # Range query with PER PARTITION LIMIT and LIMIT + # Reproduces #5361, #5363: + assert_rows(execute(cql, table, "SELECT a, b, e, count(b), max(e) FROM %s GROUP BY a, b PER PARTITION LIMIT 1 LIMIT 2"), + row(1, 2, 6, 2, 12), + row(2, 2, 6, 1, 6)) + + assert_rows(execute(cql, table, "SELECT a, b, e, count(b), max(e) FROM %s GROUP BY a PER PARTITION LIMIT 2"), + row(1, 2, 6, 4, 24), + row(2, 2, 6, 2, 12), + row(4, 8, 24, 1, 24)) + + # Range queries without aggregates and with LIMIT + assert_rows(execute(cql, table, "SELECT a, b, c, d FROM %s GROUP BY a, b, c LIMIT 3"), + row(1, 2, 1, 3), + row(1, 2, 2, 6), + row(1, 4, 2, 6)) + + # Reproduces #5362: + assert_rows(execute(cql, table, "SELECT a, b, c, d FROM %s GROUP BY a, b LIMIT 3"), + row(1, 2, 1, 3), + row(1, 4, 2, 6), + row(2, 2, 3, 3)) + + # Range queries with wildcard and with LIMIT + assert_rows(execute(cql, table, "SELECT * FROM %s GROUP BY a, b, c LIMIT 3"), + row(1, 2, 1, 3, 6), + row(1, 2, 2, 6, 12), + row(1, 4, 2, 6, 12)) + + # Reproduces #5362: + assert_rows(execute(cql, table, "SELECT * FROM %s GROUP BY a, b LIMIT 3"), + row(1, 2, 1, 3, 6), + row(1, 4, 2, 6, 12), + row(2, 2, 3, 3, 6)) + + # Range queries without aggregates and with PER PARTITION LIMIT + assert_rows(execute(cql, table, "SELECT a, b, c, d FROM %s GROUP BY a, b, c PER PARTITION LIMIT 2"), + row(1, 2, 1, 3), + row(1, 2, 2, 6), + row(2, 2, 3, 3), + row(2, 4, 3, 6), + row(4, 8, 2, 12)) + + assert_rows(execute(cql, table, "SELECT a, b, c, d FROM %s GROUP BY a, b PER PARTITION LIMIT 1"), + row(1, 2, 1, 3), + row(2, 2, 3, 3), + row(4, 8, 2, 12)) + + # Range queries with wildcard and with PER PARTITION LIMIT + assert_rows(execute(cql, table, "SELECT * FROM %s GROUP BY a, b, c PER PARTITION LIMIT 2"), + row(1, 2, 1, 3, 6), + row(1, 2, 2, 6, 12), + row(2, 2, 3, 3, 6), + row(2, 4, 3, 6, 12), + row(4, 8, 2, 12, 24)) + + assert_rows(execute(cql, table, "SELECT * FROM %s GROUP BY a, b PER PARTITION LIMIT 1"), + row(1, 2, 1, 3, 6), + row(2, 2, 3, 3, 6), + row(4, 8, 2, 12, 24)) + + # Range queries without aggregates, with PER PARTITION LIMIT and LIMIT + assert_rows(execute(cql, table, "SELECT a, b, c, d FROM %s GROUP BY a, b, c PER PARTITION LIMIT 2 LIMIT 3"), + row(1, 2, 1, 3), + row(1, 2, 2, 6), + row(2, 2, 3, 3)) + + # Range queries with wildcard, with PER PARTITION LIMIT and LIMIT + assert_rows(execute(cql, table, "SELECT * FROM %s GROUP BY a, b, c PER PARTITION LIMIT 2 LIMIT 3"), + row(1, 2, 1, 3, 6), + row(1, 2, 2, 6, 12), + row(2, 2, 3, 3, 6)) + + # Range query with DISTINCT + assert_rows(execute(cql, table, "SELECT DISTINCT a, count(a)FROM %s GROUP BY a"), + row(1, 1), + row(2, 1), + row(4, 1)) + + # Reproduces #12479: + assertInvalidMessage(cql, table, "Grouping on clustering columns is not allowed for SELECT DISTINCT queries", + "SELECT DISTINCT a, count(a)FROM %s GROUP BY a, b") + + # Range query with DISTINCT and LIMIT + # Reproduces #5361: + assert_rows(execute(cql, table, "SELECT DISTINCT a, count(a)FROM %s GROUP BY a LIMIT 2"), + row(1, 1), + row(2, 1)) + + # Reproduces #12479: + assertInvalidMessage(cql, table, "Grouping on clustering columns is not allowed for SELECT DISTINCT queries", + "SELECT DISTINCT a, count(a)FROM %s GROUP BY a, b LIMIT 2") + + # Range query with ORDER BY + assertInvalidMessage(cql, table, "ORDER BY is only supported when the partition key is restricted by an EQ or an IN", + "SELECT a, b, c, count(b), max(e) FROM %s GROUP BY a, b ORDER BY b DESC, c DESC") + + # Single partition queries + assert_rows(execute(cql, table, "SELECT a, b, e, count(b), max(e) FROM %s WHERE a = 1 GROUP BY a, b, c"), + row(1, 2, 6, 1, 6), + row(1, 2, 12, 1, 12), + row(1, 4, 12, 2, 24)) + + assert_rows(execute(cql, table, "SELECT a, b, e, count(b), max(e) FROM %s WHERE a = 1 GROUP BY b, c"), + row(1, 2, 6, 1, 6), + row(1, 2, 12, 1, 12), + row(1, 4, 12, 2, 24)) + + assert_rows(execute(cql, table, "SELECT a, b, e, count(b), max(e) FROM %s WHERE a = 1 AND b = 2 GROUP BY a, b, c"), + row(1, 2, 6, 1, 6), + row(1, 2, 12, 1, 12)) + + assert_rows(execute(cql, table, "SELECT a, b, e, count(b), max(e) FROM %s WHERE a = 1 AND b = 2 GROUP BY a, c"), + row(1, 2, 6, 1, 6), + row(1, 2, 12, 1, 12)) + + assert_rows(execute(cql, table, "SELECT a, b, e, count(b), max(e) FROM %s WHERE a = 1 AND b = 2 GROUP BY c"), + row(1, 2, 6, 1, 6), + row(1, 2, 12, 1, 12)) + + # Single partition queries without aggregates + assert_rows(execute(cql, table, "SELECT a, b, c, d FROM %s WHERE a = 1 GROUP BY a, b"), + row(1, 2, 1, 3), + row(1, 4, 2, 6)) + + assert_rows(execute(cql, table, "SELECT a, b, c, d FROM %s WHERE a = 1 GROUP BY a, b, c"), + row(1, 2, 1, 3), + row(1, 2, 2, 6), + row(1, 4, 2, 6)) + + assert_rows(execute(cql, table, "SELECT a, b, c, d FROM %s WHERE a = 1 GROUP BY b, c"), + row(1, 2, 1, 3), + row(1, 2, 2, 6), + row(1, 4, 2, 6)) + + # Reproduces #4244: + assert_rows(execute(cql, table, "SELECT a, b, c, d FROM %s WHERE a = 1 and token(a) = token(1) GROUP BY b, c"), + row(1, 2, 1, 3), + row(1, 2, 2, 6), + row(1, 4, 2, 6)) + + # Single partition queries with wildcard + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE a = 1 GROUP BY a, b, c"), + row(1, 2, 1, 3, 6), + row(1, 2, 2, 6, 12), + row(1, 4, 2, 6, 12)) + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE a = 1 GROUP BY a, b"), + row(1, 2, 1, 3, 6), + row(1, 4, 2, 6, 12)) + + # Single partition queries with DISTINCT + assert_rows(execute(cql, table, "SELECT DISTINCT a, count(a)FROM %s WHERE a = 1 GROUP BY a"), + row(1, 1)) + + # Reproduces #12479: + assertInvalidMessage(cql, table, "Grouping on clustering columns is not allowed for SELECT DISTINCT queries", + "SELECT DISTINCT a, count(a)FROM %s WHERE a = 1 GROUP BY a, b") + + # Single partition queries with LIMIT + assert_rows(execute(cql, table, "SELECT a, b, e, count(b), max(e) FROM %s WHERE a = 1 GROUP BY a, b, c LIMIT 10"), + row(1, 2, 6, 1, 6), + row(1, 2, 12, 1, 12), + row(1, 4, 12, 2, 24)) + + # Reproduces #5361: + assert_rows(execute(cql, table, "SELECT a, b, e, count(b), max(e) FROM %s WHERE a = 1 GROUP BY a, b, c LIMIT 2"), + row(1, 2, 6, 1, 6), + row(1, 2, 12, 1, 12)) + + assert_rows(execute(cql, table, "SELECT count(b), max(e) FROM %s WHERE a = 1 GROUP BY a, b, c LIMIT 1"), + row(1, 6)) + + # Single partition queries with PER PARTITION LIMIT + assert_rows(execute(cql, table, "SELECT a, b, e, count(b), max(e) FROM %s WHERE a = 1 GROUP BY a, b, c PER PARTITION LIMIT 10"), + row(1, 2, 6, 1, 6), + row(1, 2, 12, 1, 12), + row(1, 4, 12, 2, 24)) + + # Reproduces #5363: + assert_rows(execute(cql, table, "SELECT a, b, e, count(b), max(e) FROM %s WHERE a = 1 GROUP BY a, b, c PER PARTITION LIMIT 2"), + row(1, 2, 6, 1, 6), + row(1, 2, 12, 1, 12)) + + assert_rows(execute(cql, table, "SELECT count(b), max(e) FROM %s WHERE a = 1 GROUP BY a, b, c PER PARTITION LIMIT 1"), + row(1, 6)) + + # Single partition queries without aggregates and with LIMIT + # Reproduces #5362: + assert_rows(execute(cql, table, "SELECT a, b, c, d FROM %s WHERE a = 1 GROUP BY a, b LIMIT 2"), + row(1, 2, 1, 3), + row(1, 4, 2, 6)) + + assert_rows(execute(cql, table, "SELECT a, b, c, d FROM %s WHERE a = 1 GROUP BY a, b LIMIT 1"), + row(1, 2, 1, 3)) + + assert_rows(execute(cql, table, "SELECT a, b, c, d FROM %s WHERE a = 1 GROUP BY a, b, c LIMIT 2"), + row(1, 2, 1, 3), + row(1, 2, 2, 6)) + + # Single partition queries with wildcard and with LIMIT + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE a = 1 GROUP BY a, b, c LIMIT 2"), + row(1, 2, 1, 3, 6), + row(1, 2, 2, 6, 12)) + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE a = 1 GROUP BY a, b LIMIT 1"), + row(1, 2, 1, 3, 6)) + + # Single partition queries without aggregates and with PER PARTITION LIMIT + # Reproduces #5363: + assert_rows(execute(cql, table, "SELECT a, b, c, d FROM %s WHERE a = 1 GROUP BY a, b PER PARTITION LIMIT 2"), + row(1, 2, 1, 3), + row(1, 4, 2, 6)) + + assert_rows(execute(cql, table, "SELECT a, b, c, d FROM %s WHERE a = 1 GROUP BY a, b PER PARTITION LIMIT 1"), + row(1, 2, 1, 3)) + + assert_rows(execute(cql, table, "SELECT a, b, c, d FROM %s WHERE a = 1 GROUP BY a, b, c PER PARTITION LIMIT 2"), + row(1, 2, 1, 3), + row(1, 2, 2, 6)) + + # Single partition queries with wildcard and with PER PARTITION LIMIT + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE a = 1 GROUP BY a, b, c PER PARTITION LIMIT 2"), + row(1, 2, 1, 3, 6), + row(1, 2, 2, 6, 12)) + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE a = 1 GROUP BY a, b PER PARTITION LIMIT 1"), + row(1, 2, 1, 3, 6)) + + # Single partition queries with ORDER BY + assert_rows(execute(cql, table, "SELECT a, b, e, count(b), max(e) FROM %s WHERE a = 1 GROUP BY a, b, c ORDER BY b DESC, c DESC"), + row(1, 4, 24, 2, 24), + row(1, 2, 12, 1, 12), + row(1, 2, 6, 1, 6)) + + # Single partition queries with ORDER BY and PER PARTITION LIMIT + # Reproduces #5363: + assert_rows(execute(cql, table, "SELECT a, b, e, count(b), max(e) FROM %s WHERE a = 1 GROUP BY a, b, c ORDER BY b DESC, c DESC PER PARTITION LIMIT 1"), + row(1, 4, 24, 2, 24)) + + # Single partition queries with ORDER BY and LIMIT + # Reproduces #5361: + assert_rows(execute(cql, table, "SELECT a, b, e, count(b), max(e) FROM %s WHERE a = 1 GROUP BY a, b, c ORDER BY b DESC, c DESC LIMIT 2"), + row(1, 4, 24, 2, 24), + row(1, 2, 12, 1, 12)) + + # Multi-partitions queries + assert_rows(execute(cql, table, "SELECT a, b, e, count(b), max(e) FROM %s WHERE a IN (1, 2, 4) GROUP BY a, b, c"), + row(1, 2, 6, 1, 6), + row(1, 2, 12, 1, 12), + row(1, 4, 12, 2, 24), + row(2, 2, 6, 1, 6), + row(2, 4, 12, 1, 12), + row(4, 8, 24, 1, 24)) + + assert_rows(execute(cql, table, "SELECT a, b, e, count(b), max(e) FROM %s WHERE a IN (1, 2, 4) AND b = 2 GROUP BY a, b, c"), + row(1, 2, 6, 1, 6), + row(1, 2, 12, 1, 12), + row(2, 2, 6, 1, 6)) + + # Multi-partitions queries without aggregates + assert_rows(execute(cql, table, "SELECT a, b, c, d FROM %s WHERE a IN (1, 2, 4) GROUP BY a, b"), + row(1, 2, 1, 3), + row(1, 4, 2, 6), + row(2, 2, 3, 3), + row(2, 4, 3, 6), + row(4, 8, 2, 12)) + + assert_rows(execute(cql, table, "SELECT a, b, c, d FROM %s WHERE a IN (1, 2, 4) GROUP BY a, b, c"), + row(1, 2, 1, 3), + row(1, 2, 2, 6), + row(1, 4, 2, 6), + row(2, 2, 3, 3), + row(2, 4, 3, 6), + row(4, 8, 2, 12)) + + # Multi-partitions with wildcard + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE a IN (1, 2, 4) GROUP BY a, b, c"), + row(1, 2, 1, 3, 6), + row(1, 2, 2, 6, 12), + row(1, 4, 2, 6, 12), + row(2, 2, 3, 3, 6), + row(2, 4, 3, 6, 12), + row(4, 8, 2, 12, 24)) + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE a IN (1, 2, 4) GROUP BY a, b"), + row(1, 2, 1, 3, 6), + row(1, 4, 2, 6, 12), + row(2, 2, 3, 3, 6), + row(2, 4, 3, 6, 12), + row(4, 8, 2, 12, 24)) + + # Multi-partitions query with DISTINCT + assert_rows(execute(cql, table, "SELECT DISTINCT a, count(a)FROM %s WHERE a IN (1, 2, 4) GROUP BY a"), + row(1, 1), + row(2, 1), + row(4, 1)) + + # Reproduces #12479: + assertInvalidMessage(cql, table, "Grouping on clustering columns is not allowed for SELECT DISTINCT queries", + "SELECT DISTINCT a, count(a)FROM %s WHERE a IN (1, 2, 4) GROUP BY a, b") + + # Multi-partitions query with DISTINCT and LIMIT + # Reproduces #5361: + assert_rows(execute(cql, table, "SELECT DISTINCT a, count(a)FROM %s WHERE a IN (1, 2, 4) GROUP BY a LIMIT 2"), + row(1, 1), + row(2, 1)) + + # Multi-partitions queries with PER PARTITION LIMIT + # Reproduces #5363: + assert_rows(execute(cql, table, "SELECT a, b, e, count(b), max(e) FROM %s WHERE a IN (1, 2, 4) GROUP BY a, b, c PER PARTITION LIMIT 1"), + row(1, 2, 6, 1, 6), + row(2, 2, 6, 1, 6), + row(4, 8, 24, 1, 24)) + + assert_rows(execute(cql, table, "SELECT a, b, e, count(b), max(e) FROM %s WHERE a IN (1, 2, 4) GROUP BY a, b, c PER PARTITION LIMIT 2"), + row(1, 2, 6, 1, 6), + row(1, 2, 12, 1, 12), + row(2, 2, 6, 1, 6), + row(2, 4, 12, 1, 12), + row(4, 8, 24, 1, 24)) + + # Multi-partitions with wildcard and PER PARTITION LIMIT + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE a IN (1, 2, 4) GROUP BY a, b, c PER PARTITION LIMIT 2"), + row(1, 2, 1, 3, 6), + row(1, 2, 2, 6, 12), + row(2, 2, 3, 3, 6), + row(2, 4, 3, 6, 12), + row(4, 8, 2, 12, 24)) + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE a IN (1, 2, 4) GROUP BY a, b PER PARTITION LIMIT 1"), + row(1, 2, 1, 3, 6), + row(2, 2, 3, 3, 6), + row(4, 8, 2, 12, 24)) + + # Multi-partitions queries with ORDER BY + # (NYH: note that because the partition order isn't known, we can't + # actually check the result order here, hence I added ignoring_order. + # this makes this test weaker). + assert_rows_ignoring_order(execute_without_paging(cql, table, "SELECT a, b, c, count(b), max(e) FROM %s WHERE a IN (1, 2, 4) GROUP BY a, b ORDER BY b DESC, c DESC"), + row(4, 8, 2, 1, 24), + row(2, 4, 3, 1, 12), + row(1, 4, 2, 2, 24), + row(2, 2, 3, 1, 6), + row(1, 2, 2, 2, 12)) + + assert_rows_ignoring_order(execute_without_paging(cql, table, "SELECT a, b, c, d FROM %s WHERE a IN (1, 2, 4) GROUP BY a, b, c ORDER BY b DESC, c DESC"), + row(4, 8, 2, 12), + row(2, 4, 3, 6), + row(1, 4, 2, 12), + row(2, 2, 3, 3), + row(1, 2, 2, 6), + row(1, 2, 1, 3)) + + # Multi-partitions queries with ORDER BY and LIMIT + # NYH: with LIMIT, even ignoring_order is not enough, the LIMIT + # may cut it in the wrong place. I unfortunately had to comment + # out these tests. + #assert_rows_ignoring_order(execute_without_paging(cql, table, "SELECT a, b, c, d FROM %s WHERE a IN (1, 2, 4) GROUP BY a, b ORDER BY b DESC, c DESC LIMIT 3"), + # row(4, 8, 2, 12), + # row(2, 4, 3, 6), + # row(1, 4, 2, 12)) + + # Multi-partitions with wildcard, ORDER BY and LIMIT + #assert_rows_ignoring_order(execute_without_paging(cql, table, "SELECT * FROM %s WHERE a IN (1, 2, 4) GROUP BY a, b, c ORDER BY b DESC, c DESC LIMIT 3"), + # row(4, 8, 2, 12, 24), + # row(2, 4, 3, 6, 12), + # row(1, 4, 2, 12, 24)) + + # Invalid queries + assertInvalidMessage(cql, table, "Group by", + "SELECT a, b, d, count(b), max(c) FROM %s WHERE a = 1 GROUP BY a, e") + + assertInvalidMessage(cql, table, "Group by", + "SELECT a, b, d, count(b), max(c) FROM %s WHERE a = 1 GROUP BY c") + + assertInvalidMessage(cql, table, "Group by", + "SELECT a, b, d, count(b), max(c) FROM %s WHERE a = 1 GROUP BY a, c, b") + + assertInvalidMessage(cql, table, "Group by", + "SELECT a, b, d, count(b), max(c) FROM %s WHERE a = 1 GROUP BY a, a") + + assertInvalidMessage(cql, table, "Group by", + "SELECT a, b, c, d FROM %s WHERE token(a) = token(1) GROUP BY b, c") + + assertInvalidMessage(cql, table, "clustering1", + "SELECT a, b as clustering1, max(c) FROM %s WHERE a = 1 GROUP BY a, clustering1") + + assertInvalidMessage(cql, table, "z", + "SELECT a, b, max(c) FROM %s WHERE a = 1 GROUP BY a, b, z") + + # Test with composite partition key + with create_table(cql, test_keyspace, "(a int, b int, c int, d int, e int, PRIMARY KEY ((a, b), c, d)) WITH COMPACT STORAGE") as table: + execute(cql, table, "INSERT INTO %s (a, b, c, d, e) VALUES (1, 1, 1, 3, 6)") + execute(cql, table, "INSERT INTO %s (a, b, c, d, e) VALUES (1, 1, 2, 6, 12)") + execute(cql, table, "INSERT INTO %s (a, b, c, d, e) VALUES (1, 1, 3, 12, 24)") + execute(cql, table, "INSERT INTO %s (a, b, c, d, e) VALUES (1, 2, 1, 12, 24)") + execute(cql, table, "INSERT INTO %s (a, b, c, d, e) VALUES (1, 2, 2, 6, 12)") + + assertInvalidMessage(cql, table, "partition key", + "SELECT a, b, max(d) FROM %s GROUP BY a") + + assert_rows(execute(cql, table, "SELECT a, b, max(d) FROM %s GROUP BY a, b"), + row(1, 2, 12), + row(1, 1, 12)) + + assert_rows(execute(cql, table, "SELECT a, b, max(d) FROM %s WHERE a = 1 AND b = 1 GROUP BY b"), + row(1, 1, 12)) + + # Test with table without clustering key + with create_table(cql, test_keyspace, "(a int primary key, b int, c int) WITH COMPACT STORAGE") as table: + execute(cql, table, "INSERT INTO %s (a, b, c) VALUES (1, 3, 6)") + execute(cql, table, "INSERT INTO %s (a, b, c) VALUES (2, 6, 12)") + execute(cql, table, "INSERT INTO %s (a, b, c) VALUES (3, 12, 24)") + + assertInvalidMessage(cql, table, "Group by", + "SELECT a, max(c) FROM %s WHERE a = 1 GROUP BY a, a") + +def testGroupByWithoutPagingWithDeletions(cql, test_keyspace): + with create_table(cql, test_keyspace, "(a int, b int, c int, d int, e int, PRIMARY KEY (a, b, c, d)) WITH COMPACT STORAGE") as table: + execute(cql, table, "INSERT INTO %s (a, b, c, d, e) VALUES (1, 2, 1, 3, 6)") + execute(cql, table, "INSERT INTO %s (a, b, c, d, e) VALUES (1, 2, 1, 6, 12)") + execute(cql, table, "INSERT INTO %s (a, b, c, d, e) VALUES (1, 2, 1, 9, 18)") + execute(cql, table, "INSERT INTO %s (a, b, c, d, e) VALUES (1, 2, 1, 12, 24)") + execute(cql, table, "INSERT INTO %s (a, b, c, d, e) VALUES (1, 2, 2, 3, 6)") + execute(cql, table, "INSERT INTO %s (a, b, c, d, e) VALUES (1, 2, 2, 6, 12)") + execute(cql, table, "INSERT INTO %s (a, b, c, d, e) VALUES (1, 2, 2, 9, 18)") + execute(cql, table, "INSERT INTO %s (a, b, c, d, e) VALUES (1, 2, 2, 12, 24)") + execute(cql, table, "INSERT INTO %s (a, b, c, d, e) VALUES (1, 2, 3, 3, 6)") + execute(cql, table, "INSERT INTO %s (a, b, c, d, e) VALUES (1, 2, 3, 6, 12)") + execute(cql, table, "INSERT INTO %s (a, b, c, d, e) VALUES (1, 2, 3, 9, 18)") + execute(cql, table, "INSERT INTO %s (a, b, c, d, e) VALUES (1, 2, 3, 12, 24)") + + execute(cql, table, "DELETE FROM %s WHERE a = 1 AND b = 2 AND c = 1 AND d = 12") + execute(cql, table, "DELETE FROM %s WHERE a = 1 AND b = 2 AND c = 2 AND d = 9") + + assert_rows(execute(cql, table, "SELECT a, b, c, count(b), max(d) FROM %s GROUP BY a, b, c"), + row(1, 2, 1, 3, 9), + row(1, 2, 2, 3, 12), + row(1, 2, 3, 4, 12)) + +@pytest.mark.xfail(reason="issue #5361, #5363") +def testGroupByWithRangeNamesQueryWithoutPaging(cql, test_keyspace): + with create_table(cql, test_keyspace, "(a int, b int, c int, d int, PRIMARY KEY (a, b, c)) WITH COMPACT STORAGE") as table: + for i in range(1, 5): + for j in range(1, 5): + for k in range(1, 5): + execute(cql, table, "INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", i, j, k, i + j) + + # Makes sure that we have some tombstones + execute(cql, table, "DELETE FROM %s WHERE a = 3") + + # Range queries + assert_rows(execute(cql, table, "SELECT a, b, d, count(b), max(d) FROM %s WHERE b = 1 and c IN (1, 2) GROUP BY a ALLOW FILTERING"), + row(1, 1, 2, 2, 2), + row(2, 1, 3, 2, 3), + row(4, 1, 5, 2, 5)) + + assert_rows(execute(cql, table, "SELECT a, b, d, count(b), max(d) FROM %s WHERE b = 1 and c IN (1, 2) GROUP BY a, b ALLOW FILTERING"), + row(1, 1, 2, 2, 2), + row(2, 1, 3, 2, 3), + row(4, 1, 5, 2, 5)) + + assert_rows(execute(cql, table, "SELECT a, b, d, count(b), max(d) FROM %s WHERE b IN (1, 2) and c IN (1, 2) GROUP BY a, b ALLOW FILTERING"), + row(1, 1, 2, 2, 2), + row(1, 2, 3, 2, 3), + row(2, 1, 3, 2, 3), + row(2, 2, 4, 2, 4), + row(4, 1, 5, 2, 5), + row(4, 2, 6, 2, 6)) + + # Range queries with LIMIT + assert_rows(execute(cql, table, "SELECT a, b, d, count(b), max(d) FROM %s WHERE b = 1 and c IN (1, 2) GROUP BY a LIMIT 5 ALLOW FILTERING"), + row(1, 1, 2, 2, 2), + row(2, 1, 3, 2, 3), + row(4, 1, 5, 2, 5)) + + assert_rows(execute(cql, table, "SELECT a, b, d, count(b), max(d) FROM %s WHERE b = 1 and c IN (1, 2) GROUP BY a, b LIMIT 3 ALLOW FILTERING"), + row(1, 1, 2, 2, 2), + row(2, 1, 3, 2, 3), + row(4, 1, 5, 2, 5)) + + # Reproduces #5361: + assert_rows(execute(cql, table, "SELECT a, b, d, count(b), max(d) FROM %s WHERE b IN (1, 2) and c IN (1, 2) GROUP BY a, b LIMIT 3 ALLOW FILTERING"), + row(1, 1, 2, 2, 2), + row(1, 2, 3, 2, 3), + row(2, 1, 3, 2, 3)) + + # Range queries with PER PARTITION LIMIT + assert_rows(execute(cql, table, "SELECT a, b, d, count(b), max(d) FROM %s WHERE b = 1 and c IN (1, 2) GROUP BY a, b PER PARTITION LIMIT 2 ALLOW FILTERING"), + row(1, 1, 2, 2, 2), + row(2, 1, 3, 2, 3), + row(4, 1, 5, 2, 5)) + + # Reproduces #5363: + assert_rows(execute(cql, table, "SELECT a, b, d, count(b), max(d) FROM %s WHERE b IN (1, 2) and c IN (1, 2) GROUP BY a, b PER PARTITION LIMIT 1 ALLOW FILTERING"), + row(1, 1, 2, 2, 2), + row(2, 1, 3, 2, 3), + row(4, 1, 5, 2, 5)) + + # Range queries with PER PARTITION LIMIT and LIMIT + assert_rows(execute(cql, table, "SELECT a, b, d, count(b), max(d) FROM %s WHERE b = 1 and c IN (1, 2) GROUP BY a, b PER PARTITION LIMIT 2 LIMIT 5 ALLOW FILTERING"), + row(1, 1, 2, 2, 2), + row(2, 1, 3, 2, 3), + row(4, 1, 5, 2, 5)) + + # Reproduces #5361, #5363 + assert_rows(execute(cql, table, "SELECT a, b, d, count(b), max(d) FROM %s WHERE b IN (1, 2) and c IN (1, 2) GROUP BY a, b PER PARTITION LIMIT 1 LIMIT 2 ALLOW FILTERING"), + row(1, 1, 2, 2, 2), + row(2, 1, 3, 2, 3)) + +# SelectSingleColumn +def testClusteringColumnRelationsWithCompactStorage(cql, test_keyspace): + with create_table(cql, test_keyspace, "(a text, b int, c int, d int, PRIMARY KEY (a, b, c)) WITH COMPACT STORAGE") as table: + execute(cql, table, "insert into %s (a, b, c, d) values (?, ?, ?, ?)", "first", 1, 5, 1) + execute(cql, table, "insert into %s (a, b, c, d) values (?, ?, ?, ?)", "first", 2, 6, 2) + execute(cql, table, "insert into %s (a, b, c, d) values (?, ?, ?, ?)", "first", 3, 7, 3) + execute(cql, table, "insert into %s (a, b, c, d) values (?, ?, ?, ?)", "second", 4, 8, 4) + + assert_rows(execute(cql, table, "select * from %s where a in (?, ?)", "first", "second"), + row("first", 1, 5, 1), + row("first", 2, 6, 2), + row("first", 3, 7, 3), + row("second", 4, 8, 4)) + + assert_rows(execute(cql, table, "select * from %s where a = ? and b = ? and c in (?, ?)", "first", 2, 6, 7), + row("first", 2, 6, 2)) + + assert_rows(execute(cql, table, "select * from %s where a = ? and b in (?, ?) and c in (?, ?)", "first", 2, 3, 6, 7), + row("first", 2, 6, 2), + row("first", 3, 7, 3)) + + assert_rows(execute(cql, table, "select * from %s where a = ? and b in (?, ?) and c in (?, ?)", "first", 3, 2, 7, 6), + row("first", 2, 6, 2), + row("first", 3, 7, 3)) + + assert_rows(execute(cql, table, "select * from %s where a = ? and c in (?, ?) and b in (?, ?)", "first", 7, 6, 3, 2), + row("first", 2, 6, 2), + row("first", 3, 7, 3)) + + assert_rows(execute(cql, table, "select c, d from %s where a = ? and c in (?, ?) and b in (?, ?)", "first", 7, 6, 3, 2), + row(6, 2), + row(7, 3)) + + assert_rows(execute(cql, table, "select c, d from %s where a = ? and c in (?, ?) and b in (?, ?, ?)", "first", 7, 6, 3, 2, 3), + row(6, 2), + row(7, 3)) + + assert_rows(execute(cql, table, "select * from %s where a = ? and b in (?, ?) and c = ?", "first", 3, 2, 7), + row("first", 3, 7, 3)) + + assert_rows(execute(cql, table, "select * from %s where a = ? and b in ? and c in ?", + "first", [3, 2], [7, 6]), + row("first", 2, 6, 2), + row("first", 3, 7, 3)) + + # Check commented out because Scylla *does* allow equality check + # with NULL (and it returns nothing). + #assertInvalidMessage(cql, table, "Invalid null value for column b", + # "select * from %s where a = ? and b in ? and c in ?", "first", None, [7, 6]) + + assert_rows(execute(cql, table, "select * from %s where a = ? and c >= ? and b in (?, ?)", "first", 6, 3, 2), + row("first", 2, 6, 2), + row("first", 3, 7, 3)) + + assert_rows(execute(cql, table, "select * from %s where a = ? and c > ? and b in (?, ?)", "first", 6, 3, 2), + row("first", 3, 7, 3)) + + assert_rows(execute(cql, table, "select * from %s where a = ? and c <= ? and b in (?, ?)", "first", 6, 3, 2), + row("first", 2, 6, 2)) + + assert_rows(execute(cql, table, "select * from %s where a = ? and c < ? and b in (?, ?)", "first", 7, 3, 2), + row("first", 2, 6, 2)) + + assert_rows(execute(cql, table, "select * from %s where a = ? and c >= ? and c <= ? and b in (?, ?)", "first", 6, 7, 3, 2), + row("first", 2, 6, 2), + row("first", 3, 7, 3)) + + assert_rows(execute(cql, table, "select * from %s where a = ? and c > ? and c <= ? and b in (?, ?)", "first", 6, 7, 3, 2), + row("first", 3, 7, 3)) + + assertEmpty(execute(cql, table, "select * from %s where a = ? and c > ? and c < ? and b in (?, ?)", "first", 6, 7, 3, 2)) + + # Whereas Cassandra doesn't allow the seemingly-non-useful filter + # "c = ? AND c > ?", Scylla does allow them, intentionally (see + # discussion in issue #12472. So we commented out these checks: + #assertInvalidMessage(cql, table, "Column \"c\" cannot be restricted by both an equality and an inequality relation", + # "select * from %s where a = ? and c > ? and c = ? and b in (?, ?)", "first", 6, 7, 3, 2) + # + #assertInvalidMessage(cql, table, "c cannot be restricted by more than one relation if it includes an Equal", + # "select * from %s where a = ? and c = ? and c > ? and b in (?, ?)", "first", 6, 7, 3, 2) + + assert_rows(execute(cql, table, "select * from %s where a = ? and c in (?, ?) and b in (?, ?) order by b DESC", + "first", 7, 6, 3, 2), + row("first", 3, 7, 3), + row("first", 2, 6, 2)) + + #assertInvalidMessage(cql, table, "More than one restriction was found for the start bound on b", + # "select * from %s where a = ? and b > ? and b > ?", "first", 6, 3, 2) + # + #assertInvalidMessage(cql, table, "More than one restriction was found for the end bound on b", + # "select * from %s where a = ? and b < ? and b <= ?", "first", 6, 3, 2) + +# SelectTest +# Check query with KEY IN clause for wide row tables +# migrated from cql_tests.py:TestCQL.in_clause_wide_rows_test() +def testSelectKeyInForWideRows(cql, test_keyspace): + with create_table(cql, test_keyspace, "(k int, c int, v int, PRIMARY KEY (k, c)) WITH COMPACT STORAGE") as table: + for i in range(10): + execute(cql, table, "INSERT INTO %s (k, c, v) VALUES (0, ?, ?)", i, i) + + assert_rows(execute(cql, table, "SELECT v FROM %s WHERE k = 0 AND c IN (5, 2, 8)"), + row(2), row(5), row(8)) + + with create_table(cql, test_keyspace, "(k int, c1 int, c2 int, v int, PRIMARY KEY (k, c1, c2)) WITH COMPACT STORAGE") as table: + for i in range(10): + execute(cql, table, "INSERT INTO %s (k, c1, c2, v) VALUES (0, 0, ?, ?)", i, i) + + assertEmpty(execute(cql, table, "SELECT v FROM %s WHERE k = 0 AND c1 IN (5, 2, 8) AND c2 = 3")) + + assert_rows(execute(cql, table, "SELECT v FROM %s WHERE k = 0 AND c1 = 0 AND c2 IN (5, 2, 8)"), + row(2), row(5), row(8)) + +# Check SELECT respects inclusive and exclusive bounds +# migrated from cql_tests.py:TestCQL.exclusive_slice_test() +def testSelectBounds(cql, test_keyspace): + with create_table(cql, test_keyspace, "(k int, c int, v int, PRIMARY KEY (k, c)) WITH COMPACT STORAGE") as table: + for i in range(10): + execute(cql, table, "INSERT INTO %s (k, c, v) VALUES (0, ?, ?)", i, i) + + assertRowCount(execute(cql, table, "SELECT v FROM %s WHERE k = 0"), 10) + + assert_rows(execute(cql, table, "SELECT v FROM %s WHERE k = 0 AND c >= 2 AND c <= 6"), + row(2), row(3), row(4), row(5), row(6)) + + assert_rows(execute(cql, table, "SELECT v FROM %s WHERE k = 0 AND c > 2 AND c <= 6"), + row(3), row(4), row(5), row(6)) + + assert_rows(execute(cql, table, "SELECT v FROM %s WHERE k = 0 AND c >= 2 AND c < 6"), + row(2), row(3), row(4), row(5)) + + assert_rows(execute(cql, table, "SELECT v FROM %s WHERE k = 0 AND c > 2 AND c < 6"), + row(3), row(4), row(5)) + + assert_rows(execute(cql, table, "SELECT v FROM %s WHERE k = 0 AND c > 2 AND c <= 6 LIMIT 2"), + row(3), row(4)) + + assert_rows(execute(cql, table, "SELECT v FROM %s WHERE k = 0 AND c >= 2 AND c < 6 ORDER BY c DESC LIMIT 2"), + row(5), row(4)) + +# Test for CASSANDRA-4716 bug and more generally for good behavior of ordering, +# migrated from cql_tests.py:TestCQL.reversed_compact_test() +def testReverseCompact(cql, test_keyspace): + with create_table(cql, test_keyspace, "(k text, c int, v int, PRIMARY KEY (k, c)) WITH COMPACT STORAGE AND CLUSTERING ORDER BY (c DESC)") as table: + for i in range(10): + execute(cql, table, "INSERT INTO %s (k, c, v) VALUES ('foo', ?, ?)", i, i) + + assert_rows(execute(cql, table, "SELECT c FROM %s WHERE c > 2 AND c < 6 AND k = 'foo'"), + row(5), row(4), row(3)) + + assert_rows(execute(cql, table, "SELECT c FROM %s WHERE c >= 2 AND c <= 6 AND k = 'foo'"), + row(6), row(5), row(4), row(3), row(2)) + + assert_rows(execute(cql, table, "SELECT c FROM %s WHERE c > 2 AND c < 6 AND k = 'foo' ORDER BY c ASC"), + row(3), row(4), row(5)) + + assert_rows(execute(cql, table, "SELECT c FROM %s WHERE c >= 2 AND c <= 6 AND k = 'foo' ORDER BY c ASC"), + row(2), row(3), row(4), row(5), row(6)) + + assert_rows(execute(cql, table, "SELECT c FROM %s WHERE c > 2 AND c < 6 AND k = 'foo' ORDER BY c DESC"), + row(5), row(4), row(3)) + + assert_rows(execute(cql, table, "SELECT c FROM %s WHERE c >= 2 AND c <= 6 AND k = 'foo' ORDER BY c DESC"), + row(6), row(5), row(4), row(3), row(2)) + + with create_table(cql, test_keyspace, "(k text, c int, v int, PRIMARY KEY (k, c)) WITH COMPACT STORAGE") as table: + for i in range(10): + execute(cql, table, "INSERT INTO %s(k, c, v) VALUES ('foo', ?, ?)", i, i) + + assert_rows(execute(cql, table, "SELECT c FROM %s WHERE c > 2 AND c < 6 AND k = 'foo'"), + row(3), row(4), row(5)) + + assert_rows(execute(cql, table, "SELECT c FROM %s WHERE c >= 2 AND c <= 6 AND k = 'foo'"), + row(2), row(3), row(4), row(5), row(6)) + + assert_rows(execute(cql, table, "SELECT c FROM %s WHERE c > 2 AND c < 6 AND k = 'foo' ORDER BY c ASC"), + row(3), row(4), row(5)) + + assert_rows(execute(cql, table, "SELECT c FROM %s WHERE c >= 2 AND c <= 6 AND k = 'foo' ORDER BY c ASC"), + row(2), row(3), row(4), row(5), row(6)) + + assert_rows(execute(cql, table, "SELECT c FROM %s WHERE c > 2 AND c < 6 AND k = 'foo' ORDER BY c DESC"), + row(5), row(4), row(3)) + + assert_rows(execute(cql, table, "SELECT c FROM %s WHERE c >= 2 AND c <= 6 AND k = 'foo' ORDER BY c DESC"), + row(6), row(5), row(4), row(3), row(2)) + +# Test for the bug from CASSANDRA-4760 and CASSANDRA-4759, +# migrated from cql_tests.py:TestCQL.reversed_compact_multikey_test() +def testReversedCompactMultikey(cql, test_keyspace): + with create_table(cql, test_keyspace, "(key text, c1 int, c2 int, value text, PRIMARY KEY (key, c1, c2)) WITH COMPACT STORAGE AND CLUSTERING ORDER BY (c1 DESC, c2 DESC)") as table: + for i in range(3): + for j in range(3): + execute(cql, table, "INSERT INTO %s (key, c1, c2, value) VALUES ('foo', ?, ?, 'bar')", i, j) + + # Equalities + assert_rows(execute(cql, table, "SELECT c1, c2 FROM %s WHERE key='foo' AND c1 = 1"), + row(1, 2), row(1, 1), row(1, 0)) + + assert_rows(execute(cql, table, "SELECT c1, c2 FROM %s WHERE key='foo' AND c1 = 1 ORDER BY c1 ASC, c2 ASC"), + row(1, 0), row(1, 1), row(1, 2)) + + assert_rows(execute(cql, table, "SELECT c1, c2 FROM %s WHERE key='foo' AND c1 = 1 ORDER BY c1 DESC, c2 DESC"), + row(1, 2), row(1, 1), row(1, 0)) + + # GT + assert_rows(execute(cql, table, "SELECT c1, c2 FROM %s WHERE key='foo' AND c1 > 1"), + row(2, 2), row(2, 1), row(2, 0)) + + assert_rows(execute(cql, table, "SELECT c1, c2 FROM %s WHERE key='foo' AND c1 > 1 ORDER BY c1 ASC, c2 ASC"), + row(2, 0), row(2, 1), row(2, 2)) + + assert_rows(execute(cql, table, "SELECT c1, c2 FROM %s WHERE key='foo' AND c1 > 1 ORDER BY c1 DESC, c2 DESC"), + row(2, 2), row(2, 1), row(2, 0)) + + assert_rows(execute(cql, table, "SELECT c1, c2 FROM %s WHERE key='foo' AND c1 >= 1"), + row(2, 2), row(2, 1), row(2, 0), row(1, 2), row(1, 1), row(1, 0)) + + assert_rows(execute(cql, table, "SELECT c1, c2 FROM %s WHERE key='foo' AND c1 >= 1 ORDER BY c1 ASC, c2 ASC"), + row(1, 0), row(1, 1), row(1, 2), row(2, 0), row(2, 1), row(2, 2)) + + assert_rows(execute(cql, table, "SELECT c1, c2 FROM %s WHERE key='foo' AND c1 >= 1 ORDER BY c1 ASC"), + row(1, 0), row(1, 1), row(1, 2), row(2, 0), row(2, 1), row(2, 2)) + + assert_rows(execute(cql, table, "SELECT c1, c2 FROM %s WHERE key='foo' AND c1 >= 1 ORDER BY c1 DESC, c2 DESC"), + row(2, 2), row(2, 1), row(2, 0), row(1, 2), row(1, 1), row(1, 0)) + + # LT + assert_rows(execute(cql, table, "SELECT c1, c2 FROM %s WHERE key='foo' AND c1 < 1"), + row(0, 2), row(0, 1), row(0, 0)) + + assert_rows(execute(cql, table, "SELECT c1, c2 FROM %s WHERE key='foo' AND c1 < 1 ORDER BY c1 ASC, c2 ASC"), + row(0, 0), row(0, 1), row(0, 2)) + + assert_rows(execute(cql, table, "SELECT c1, c2 FROM %s WHERE key='foo' AND c1 < 1 ORDER BY c1 DESC, c2 DESC"), + row(0, 2), row(0, 1), row(0, 0)) + + assert_rows(execute(cql, table, "SELECT c1, c2 FROM %s WHERE key='foo' AND c1 <= 1"), + row(1, 2), row(1, 1), row(1, 0), row(0, 2), row(0, 1), row(0, 0)) + + assert_rows(execute(cql, table, "SELECT c1, c2 FROM %s WHERE key='foo' AND c1 <= 1 ORDER BY c1 ASC, c2 ASC"), + row(0, 0), row(0, 1), row(0, 2), row(1, 0), row(1, 1), row(1, 2)) + + assert_rows(execute(cql, table, "SELECT c1, c2 FROM %s WHERE key='foo' AND c1 <= 1 ORDER BY c1 ASC"), + row(0, 0), row(0, 1), row(0, 2), row(1, 0), row(1, 1), row(1, 2)) + + assert_rows(execute(cql, table, "SELECT c1, c2 FROM %s WHERE key='foo' AND c1 <= 1 ORDER BY c1 DESC, c2 DESC"), + row(1, 2), row(1, 1), row(1, 0), row(0, 2), row(0, 1), row(0, 0)) + +# Migrated from cql_tests.py:TestCQL.multi_in_compact_non_composite_test() +def testMultiSelectsNonCompositeCompactStorage(cql, test_keyspace): + with create_table(cql, test_keyspace, "(key int, c int, v int, PRIMARY KEY (key, c)) WITH COMPACT STORAGE") as table: + execute(cql, table, "INSERT INTO %s (key, c, v) VALUES (0, 0, 0)") + execute(cql, table, "INSERT INTO %s (key, c, v) VALUES (0, 1, 1)") + execute(cql, table, "INSERT INTO %s (key, c, v) VALUES (0, 2, 2)") + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE key=0 AND c IN (0, 2)"), + row(0, 0, 0), row(0, 2, 2)) + +def testSelectDistinct(cql, test_keyspace): + # Test a 'compact storage' table. + with create_table(cql, test_keyspace, "(pk0 int, pk1 int, val int, PRIMARY KEY ((pk0, pk1))) WITH COMPACT STORAGE") as table: + for i in range(3): + execute(cql, table, "INSERT INTO %s (pk0, pk1, val) VALUES (?, ?, ?)", i, i, i) + + assert_rows(execute(cql, table, "SELECT DISTINCT pk0, pk1 FROM %s LIMIT 1"), + row(0, 0)) + + assert_rows(execute(cql, table, "SELECT DISTINCT pk0, pk1 FROM %s LIMIT 3"), + row(0, 0), + row(2, 2), + row(1, 1)) + + # Test a 'wide row' thrift table. + with create_table(cql, test_keyspace, "(pk int, name text, val int, PRIMARY KEY (pk, name)) WITH COMPACT STORAGE") as table: + for i in range(3): + execute(cql, table, "INSERT INTO %s (pk, name, val) VALUES (?, 'name0', 0)", i) + execute(cql, table, "INSERT INTO %s (pk, name, val) VALUES (?, 'name1', 1)", i) + + assert_rows(execute(cql, table, "SELECT DISTINCT pk FROM %s LIMIT 1"), + row(1)) + + assert_rows(execute(cql, table, "SELECT DISTINCT pk FROM %s LIMIT 3"), + row(1), + row(0), + row(2)) + +REQUIRES_ALLOW_FILTERING_MESSAGE = "Cannot execute this query as it might involve data filtering and thus may have unpredictable performance. If you want to execute this query despite the performance unpredictability, use ALLOW FILTERING" + +@pytest.mark.xfail(reason="issue #12526") +def testFilteringOnCompactTablesWithoutIndices(cql, test_keyspace): + # Test COMPACT table with clustering columns + with create_table(cql, test_keyspace, "(a int, b int, c int, PRIMARY KEY (a, b)) WITH COMPACT STORAGE") as table: + execute(cql, table, "INSERT INTO %s (a, b, c) VALUES (1, 2, 4)") + execute(cql, table, "INSERT INTO %s (a, b, c) VALUES (1, 3, 6)") + execute(cql, table, "INSERT INTO %s (a, b, c) VALUES (1, 4, 4)") + execute(cql, table, "INSERT INTO %s (a, b, c) VALUES (2, 3, 7)") + + # Adds tomstones + execute(cql, table, "INSERT INTO %s (a, b, c) VALUES (1, 1, 4)") + execute(cql, table, "INSERT INTO %s (a, b, c) VALUES (2, 2, 7)") + execute(cql, table, "DELETE FROM %s WHERE a = 1 AND b = 1") + execute(cql, table, "DELETE FROM %s WHERE a = 2 AND b = 2") + + for _ in before_and_after_flush(cql, table): + # Checks filtering + assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + "SELECT * FROM %s WHERE a = 1 AND b = 4 AND c = 4") + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE a = 1 AND b = 4 AND c = 4 ALLOW FILTERING"), + row(1, 4, 4)) + + assertInvalidMessage(cql, table, "IN predicates on non-primary-key columns (c) is not yet supported", + "SELECT * FROM %s WHERE a IN (1, 2) AND c IN (6, 7)") + + assertInvalidMessage(cql, table, "IN predicates on non-primary-key columns (c) is not yet supported", + "SELECT * FROM %s WHERE a IN (1, 2) AND c IN (6, 7) ALLOW FILTERING") + + assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + "SELECT * FROM %s WHERE c > 4") + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE c > 4 ALLOW FILTERING"), + row(1, 3, 6), + row(2, 3, 7)) + + assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + "SELECT * FROM %s WHERE b < 3 AND c <= 4") + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE b < 3 AND c <= 4 ALLOW FILTERING"), + row(1, 2, 4)) + + assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + "SELECT * FROM %s WHERE c >= 3 AND c <= 6") + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE c >= 3 AND c <= 6 ALLOW FILTERING"), + row(1, 2, 4), + row(1, 3, 6), + row(1, 4, 4)) + + # Checks filtering with null + # tests commented out because Scylla does support comparison with null + # (returning nothing) + #assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + # "SELECT * FROM %s WHERE c = null") + #assertInvalidMessage(cql, table, "Unsupported null value for column c", + # "SELECT * FROM %s WHERE c = null ALLOW FILTERING") + #assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + # "SELECT * FROM %s WHERE c > null") + #assertInvalidMessage(cql, table, "Unsupported null value for column c", + # "SELECT * FROM %s WHERE c > null ALLOW FILTERING") + + # Checks filtering with unset + assertInvalidMessage(cql, table, "Unsupported unset value for column c", + "SELECT * FROM %s WHERE c = ? ALLOW FILTERING", + unset()) + assertInvalidMessage(cql, table, "Unsupported unset value for column c", + "SELECT * FROM %s WHERE c > ? ALLOW FILTERING", + unset()) + + # Test COMPACT table without clustering columns + with create_table(cql, test_keyspace, "(a int PRIMARY KEY, b int, c int) WITH COMPACT STORAGE") as table: + execute(cql, table, "INSERT INTO %s (a, b, c) VALUES (1, 2, 4)") + execute(cql, table, "INSERT INTO %s (a, b, c) VALUES (2, 1, 6)") + execute(cql, table, "INSERT INTO %s (a, b, c) VALUES (3, 2, 4)") + execute(cql, table, "INSERT INTO %s (a, b, c) VALUES (4, 1, 7)") + + # Adds tomstones + execute(cql, table, "INSERT INTO %s (a, b, c) VALUES (0, 1, 4)") + execute(cql, table, "INSERT INTO %s (a, b, c) VALUES (5, 2, 7)") + execute(cql, table, "DELETE FROM %s WHERE a = 0") + execute(cql, table, "DELETE FROM %s WHERE a = 5") + + for _ in before_and_after_flush(cql, table): + + # Checks filtering + assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + "SELECT * FROM %s WHERE a = 1 AND b = 4 AND c = 4") + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE a = 1 AND b = 2 AND c = 4 ALLOW FILTERING"), + row(1, 2, 4)) + + assertInvalidMessage(cql, table, "IN predicates on non-primary-key columns (c) is not yet supported", + "SELECT * FROM %s WHERE a IN (1, 2) AND c IN (6, 7)") + + assertInvalidMessage(cql, table, "IN predicates on non-primary-key columns (c) is not yet supported", + "SELECT * FROM %s WHERE a IN (1, 2) AND c IN (6, 7) ALLOW FILTERING") + + assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + "SELECT * FROM %s WHERE c > 4") + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE c > 4 ALLOW FILTERING"), + row(2, 1, 6), + row(4, 1, 7)) + + assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + "SELECT * FROM %s WHERE b < 3 AND c <= 4") + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE b < 3 AND c <= 4 ALLOW FILTERING"), + row(1, 2, 4), + row(3, 2, 4)) + + assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + "SELECT * FROM %s WHERE c >= 3 AND c <= 6") + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE c >= 3 AND c <= 6 ALLOW FILTERING"), + row(1, 2, 4), + row(2, 1, 6), + row(3, 2, 4)) + + # Checks filtering with null + assertInvalidMessage(cql, table,REQUIRES_ALLOW_FILTERING_MESSAGE, + "SELECT * FROM %s WHERE c = null") + assertInvalidMessage(cql, table,"Unsupported null value for column c", + "SELECT * FROM %s WHERE c = null ALLOW FILTERING") + assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + "SELECT * FROM %s WHERE c > null") + assertInvalidMessage(cql, table,"Unsupported null value for column c", + "SELECT * FROM %s WHERE c > null ALLOW FILTERING") + + # // Checks filtering with unset + assertInvalidMessage(cql, table,"Unsupported unset value for column c", + "SELECT * FROM %s WHERE c = ? ALLOW FILTERING", + unset()) + assertInvalidMessage(cql, table,"Unsupported unset value for column c", + "SELECT * FROM %s WHERE c > ? ALLOW FILTERING", + unset()) + +@pytest.mark.xfail(reason="issue #12526") +def testFilteringOnCompactTablesWithoutIndicesAndWithLists(cql, test_keyspace): + # Test COMPACT table with clustering columns + with create_table(cql, test_keyspace, "(a int, b int, c frozen>, PRIMARY KEY (a, b)) WITH COMPACT STORAGE") as table: + execute(cql, table, "INSERT INTO %s (a, b, c) VALUES (1, 2, [4, 2])") + execute(cql, table, "INSERT INTO %s (a, b, c) VALUES (1, 3, [6, 2])") + execute(cql, table, "INSERT INTO %s (a, b, c) VALUES (1, 4, [4, 1])") + execute(cql, table, "INSERT INTO %s (a, b, c) VALUES (2, 3, [7, 1])") + + for _ in before_and_after_flush(cql, table): + # Checks filtering + assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + "SELECT * FROM %s WHERE a = 1 AND b = 4 AND c = [4, 1]") + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE a = 1 AND b = 4 AND c = [4, 1] ALLOW FILTERING"), + row(1, 4, [4, 1])) + + assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + "SELECT * FROM %s WHERE c > [4, 2]") + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE c > [4, 2] ALLOW FILTERING"), + row(1, 3, [6, 2]), + row(2, 3, [7, 1])) + + assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + "SELECT * FROM %s WHERE b <= 3 AND c < [6, 2]") + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE b <= 3 AND c < [6, 2] ALLOW FILTERING"), + row(1, 2, [4, 2])) + + assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + "SELECT * FROM %s WHERE c >= [4, 2] AND c <= [6, 4]") + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE c >= [4, 2] AND c <= [6, 4] ALLOW FILTERING"), + row(1, 2, [4, 2]), + row(1, 3, [6, 2])) + + assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + "SELECT * FROM %s WHERE c CONTAINS 2") + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE c CONTAINS 2 ALLOW FILTERING"), + row(1, 2, [4, 2]), + row(1, 3, [6, 2])) + + assertInvalidMessage(cql, table, "Cannot use CONTAINS KEY on non-map column c", + "SELECT * FROM %s WHERE c CONTAINS KEY 2 ALLOW FILTERING") + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE c CONTAINS 2 AND c CONTAINS 6 ALLOW FILTERING"), + row(1, 3, [6, 2])) + + # Checks filtering with null + assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + "SELECT * FROM %s WHERE c = null") + assertInvalidMessage(cql, table, "Unsupported null value for column c", + "SELECT * FROM %s WHERE c = null ALLOW FILTERING") + assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + "SELECT * FROM %s WHERE c > null") + assertInvalidMessage(cql, table, "Unsupported null value for column c", + "SELECT * FROM %s WHERE c > null ALLOW FILTERING") + assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + "SELECT * FROM %s WHERE c CONTAINS null") + assertInvalidMessage(cql, table, "Unsupported null value for column c", + "SELECT * FROM %s WHERE c CONTAINS null ALLOW FILTERING") + + # Checks filtering with unset + assertInvalidMessage(cql, table, "Unsupported unset value for column c", + "SELECT * FROM %s WHERE c = ? ALLOW FILTERING", + unset()) + assertInvalidMessage(cql, table, "Unsupported unset value for column c", + "SELECT * FROM %s WHERE c > ? ALLOW FILTERING", + unset()) + assertInvalidMessage(cql, table, "Unsupported unset value for column c", + "SELECT * FROM %s WHERE c CONTAINS ? ALLOW FILTERING", + unset()) + + # Test COMPACT table without clustering columns + with create_table(cql, test_keyspace, "(a int PRIMARY KEY, b int, c frozen>) WITH COMPACT STORAGE") as table: + execute(cql, table, "INSERT INTO %s (a, b, c) VALUES (1, 2, [4, 2])") + execute(cql, table, "INSERT INTO %s (a, b, c) VALUES (2, 1, [6, 2])") + execute(cql, table, "INSERT INTO %s (a, b, c) VALUES (3, 2, [4, 1])") + execute(cql, table, "INSERT INTO %s (a, b, c) VALUES (4, 1, [7, 1])") + + for _ in before_and_after_flush(cql, table): + # Checks filtering + assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + "SELECT * FROM %s WHERE a = 1 AND b = 2 AND c = [4, 2]") + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE a = 1 AND b = 2 AND c = [4, 2] ALLOW FILTERING"), + row(1, 2, [4, 2])) + + assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + "SELECT * FROM %s WHERE c > [4, 2]") + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE c > [4, 2] ALLOW FILTERING"), + row(2, 1, [6, 2]), + row(4, 1, [7, 1])) + + assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + "SELECT * FROM %s WHERE b < 3 AND c <= [4, 2]") + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE b < 3 AND c <= [4, 2] ALLOW FILTERING"), + row(1, 2, [4, 2]), + row(3, 2, [4, 1])) + + assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + "SELECT * FROM %s WHERE c >= [4, 3] AND c <= [7]") + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE c >= [4, 3] AND c <= [7] ALLOW FILTERING"), + row(2, 1, [6, 2])) + + assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + "SELECT * FROM %s WHERE c CONTAINS 2") + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE c CONTAINS 2 ALLOW FILTERING"), + row(1, 2, [4, 2]), + row(2, 1, [6, 2])) + + assertInvalidMessage(cql, table, "Cannot use CONTAINS KEY on non-map column c", + "SELECT * FROM %s WHERE c CONTAINS KEY 2 ALLOW FILTERING") + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE c CONTAINS 2 AND c CONTAINS 6 ALLOW FILTERING"), + row(2, 1, [6, 2])) + + # Checks filtering with null + assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + "SELECT * FROM %s WHERE c = null") + assertInvalidMessage(cql, table, "Unsupported null value for column c", + "SELECT * FROM %s WHERE c = null ALLOW FILTERING") + assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + "SELECT * FROM %s WHERE c > null") + assertInvalidMessage(cql, table, "Unsupported null value for column c", + "SELECT * FROM %s WHERE c > null ALLOW FILTERING") + assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + "SELECT * FROM %s WHERE c CONTAINS null") + assertInvalidMessage(cql, table, "Unsupported null value for column c", + "SELECT * FROM %s WHERE c CONTAINS null ALLOW FILTERING") + + # Checks filtering with unset + assertInvalidMessage(cql, table, "Unsupported unset value for column c", + "SELECT * FROM %s WHERE c = ? ALLOW FILTERING", + unset()) + assertInvalidMessage(cql, table, "Unsupported unset value for column c", + "SELECT * FROM %s WHERE c > ? ALLOW FILTERING", + unset()) + assertInvalidMessage(cql, table, "Unsupported unset value for column c", + "SELECT * FROM %s WHERE c CONTAINS ? ALLOW FILTERING", + unset()) + +@pytest.mark.xfail(reason="issue #12526") +def testFilteringOnCompactTablesWithoutIndicesAndWithSets(cql, test_keyspace): + # Test COMPACT table with clustering columns + with create_table(cql, test_keyspace, "(a int, b int, c frozen>, PRIMARY KEY (a, b)) WITH COMPACT STORAGE") as table: + execute(cql, table, "INSERT INTO %s (a, b, c) VALUES (1, 2, {4, 2})") + execute(cql, table, "INSERT INTO %s (a, b, c) VALUES (1, 3, {6, 2})") + execute(cql, table, "INSERT INTO %s (a, b, c) VALUES (1, 4, {4, 1})") + execute(cql, table, "INSERT INTO %s (a, b, c) VALUES (2, 3, {7, 1})") + + for _ in before_and_after_flush(cql, table): + # Checks filtering + assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + "SELECT * FROM %s WHERE a = 1 AND b = 4 AND c = {4, 1}") + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE a = 1 AND b = 4 AND c = {4, 1} ALLOW FILTERING"), + row(1, 4, {4, 1})) + + assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + "SELECT * FROM %s WHERE c > {4, 2}") + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE c > {4, 2} ALLOW FILTERING"), + row(1, 3, {6, 2})) + + assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + "SELECT * FROM %s WHERE b <= 3 AND c < {6, 2}") + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE b <= 3 AND c < {6, 2} ALLOW FILTERING"), + row(1, 2, {2, 4}), + row(2, 3, {1, 7})) + + assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + "SELECT * FROM %s WHERE c >= {4, 2} AND c <= {6, 4}") + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE c >= {4, 2} AND c <= {6, 4} ALLOW FILTERING"), + row(1, 2, {4, 2}), + row(1, 3, {6, 2})) + + assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + "SELECT * FROM %s WHERE c CONTAINS 2") + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE c CONTAINS 2 ALLOW FILTERING"), + row(1, 2, {4, 2}), + row(1, 3, {6, 2})) + + assertInvalidMessage(cql, table, "Cannot use CONTAINS KEY on non-map column c", + "SELECT * FROM %s WHERE c CONTAINS KEY 2 ALLOW FILTERING") + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE c CONTAINS 2 AND c CONTAINS 6 ALLOW FILTERING"), + row(1, 3, {6, 2})) + + # Checks filtering with null + assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + "SELECT * FROM %s WHERE c = null") + assertInvalidMessage(cql, table, "Unsupported null value for column c", + "SELECT * FROM %s WHERE c = null ALLOW FILTERING") + assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + "SELECT * FROM %s WHERE c > null") + assertInvalidMessage(cql, table, "Unsupported null value for column c", + "SELECT * FROM %s WHERE c > null ALLOW FILTERING") + assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + "SELECT * FROM %s WHERE c CONTAINS null") + assertInvalidMessage(cql, table, "Unsupported null value for column c", + "SELECT * FROM %s WHERE c CONTAINS null ALLOW FILTERING") + + # Checks filtering with unset + assertInvalidMessage(cql, table, "Unsupported unset value for column c", + "SELECT * FROM %s WHERE c = ? ALLOW FILTERING", + unset()) + assertInvalidMessage(cql, table, "Unsupported unset value for column c", + "SELECT * FROM %s WHERE c > ? ALLOW FILTERING", + unset()) + assertInvalidMessage(cql, table, "Unsupported unset value for column c", + "SELECT * FROM %s WHERE c CONTAINS ? ALLOW FILTERING", + unset()) + + # Test COMPACT table without clustering columns + with create_table(cql, test_keyspace, "(a int PRIMARY KEY, b int, c frozen>) WITH COMPACT STORAGE") as table: + + execute(cql, table, "INSERT INTO %s (a, b, c) VALUES (1, 2, {4, 2})") + execute(cql, table, "INSERT INTO %s (a, b, c) VALUES (2, 1, {6, 2})") + execute(cql, table, "INSERT INTO %s (a, b, c) VALUES (3, 2, {4, 1})") + execute(cql, table, "INSERT INTO %s (a, b, c) VALUES (4, 1, {7, 1})") + + for _ in before_and_after_flush(cql, table): + # Checks filtering + assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + "SELECT * FROM %s WHERE a = 1 AND b = 2 AND c = {4, 2}") + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE a = 1 AND b = 2 AND c = {4, 2} ALLOW FILTERING"), + row(1, 2, {4, 2})) + + assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + "SELECT * FROM %s WHERE c > {4, 2}") + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE c > {4, 2} ALLOW FILTERING"), + row(2, 1, {6, 2})) + + assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + "SELECT * FROM %s WHERE b < 3 AND c <= {4, 2}") + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE b < 3 AND c <= {4, 2} ALLOW FILTERING"), + row(1, 2, {4, 2}), + row(4, 1, {1, 7}), + row(3, 2, {4, 1})) + + assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + "SELECT * FROM %s WHERE c >= {4, 3} AND c <= {7}") + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE c >= {5, 2} AND c <= {7} ALLOW FILTERING"), + row(2, 1, {6, 2})) + + assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + "SELECT * FROM %s WHERE c CONTAINS 2") + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE c CONTAINS 2 ALLOW FILTERING"), + row(1, 2, {4, 2}), + row(2, 1, {6, 2})) + + assertInvalidMessage(cql, table, "Cannot use CONTAINS KEY on non-map column c", + "SELECT * FROM %s WHERE c CONTAINS KEY 2 ALLOW FILTERING") + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE c CONTAINS 2 AND c CONTAINS 6 ALLOW FILTERING"), + row(2, 1, {6, 2})) + + # Checks filtering with null + assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + "SELECT * FROM %s WHERE c = null") + assertInvalidMessage(cql, table, "Unsupported null value for column c", + "SELECT * FROM %s WHERE c = null ALLOW FILTERING") + assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + "SELECT * FROM %s WHERE c > null") + assertInvalidMessage(cql, table, "Unsupported null value for column c", + "SELECT * FROM %s WHERE c > null ALLOW FILTERING") + assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + "SELECT * FROM %s WHERE c CONTAINS null") + assertInvalidMessage(cql, table, "Unsupported null value for column c", + "SELECT * FROM %s WHERE c CONTAINS null ALLOW FILTERING") + + # Checks filtering with unset + assertInvalidMessage(cql, table, "Unsupported unset value for column c", + "SELECT * FROM %s WHERE c = ? ALLOW FILTERING", + unset()) + assertInvalidMessage(cql, table, "Unsupported unset value for column c", + "SELECT * FROM %s WHERE c > ? ALLOW FILTERING", + unset()) + assertInvalidMessage(cql, table, "Unsupported unset value for column c", + "SELECT * FROM %s WHERE c CONTAINS ? ALLOW FILTERING", + unset()) + +def testAllowFilteringOnPartitionKeyWithDistinct(cql, test_keyspace): + # Test a 'compact storage' table. + with create_table(cql, test_keyspace, "(pk0 int, pk1 int, val int, PRIMARY KEY ((pk0, pk1))) WITH COMPACT STORAGE") as table: + for i in range(3): + execute(cql, table, "INSERT INTO %s (pk0, pk1, val) VALUES (?, ?, ?)", i, i, i) + + for _ in before_and_after_flush(cql, table): + assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + "SELECT DISTINCT pk0, pk1 FROM %s WHERE pk1 = 1 LIMIT 3") + + assert_rows(execute(cql, table, "SELECT DISTINCT pk0, pk1 FROM %s WHERE pk0 < 2 AND pk1 = 1 LIMIT 1 ALLOW FILTERING"), + row(1, 1)) + + assert_rows(execute(cql, table, "SELECT DISTINCT pk0, pk1 FROM %s WHERE pk1 > 1 LIMIT 3 ALLOW FILTERING"), + row(2, 2)) + + # Test a 'wide row' thrift table. + with create_table(cql, test_keyspace, "(pk int, name text, val int, PRIMARY KEY (pk, name)) WITH COMPACT STORAGE") as table: + for i in range(3): + execute(cql, table, "INSERT INTO %s (pk, name, val) VALUES (?, 'name0', 0)", i) + execute(cql, table, "INSERT INTO %s (pk, name, val) VALUES (?, 'name1', 1)", i) + + for _ in before_and_after_flush(cql, table): + assert_rows(execute(cql, table, "SELECT DISTINCT pk FROM %s WHERE pk > 1 LIMIT 1 ALLOW FILTERING"), + row(2)) + + assert_rows(execute(cql, table, "SELECT DISTINCT pk FROM %s WHERE pk > 0 LIMIT 3 ALLOW FILTERING"), + row(1), + row(2)) + +def executeFilteringOnly(cql, table, statement): + assert_invalid(cql, table, statement) + return execute_without_paging(cql, table, statement + " ALLOW FILTERING") + +@pytest.mark.xfail(reason="issue #12526") +def testAllowFilteringOnPartitionKeyWithCounters(cql, test_keyspace): + for compactStorageClause in ["", " WITH COMPACT STORAGE"]: + with create_table(cql, test_keyspace, "(a int, b int, c int, cnt counter, PRIMARY KEY ((a, b), c)) " + compactStorageClause) as table: + execute(cql, table, "UPDATE %s SET cnt = cnt + ? WHERE a = ? AND b = ? AND c = ?", 14, 11, 12, 13) + execute(cql, table, "UPDATE %s SET cnt = cnt + ? WHERE a = ? AND b = ? AND c = ?", 24, 21, 22, 23) + execute(cql, table, "UPDATE %s SET cnt = cnt + ? WHERE a = ? AND b = ? AND c = ?", 27, 21, 22, 26) + execute(cql, table, "UPDATE %s SET cnt = cnt + ? WHERE a = ? AND b = ? AND c = ?", 34, 31, 32, 33) + execute(cql, table, "UPDATE %s SET cnt = cnt + ? WHERE a = ? AND b = ? AND c = ?", 24, 41, 42, 43) + + for _ in before_and_after_flush(cql, table): + assert_rows(executeFilteringOnly(cql, table, "SELECT * FROM %s WHERE cnt = 24"), + row(41, 42, 43, 24), + row(21, 22, 23, 24)) + assert_rows(executeFilteringOnly(cql, table, "SELECT * FROM %s WHERE b > 22 AND cnt = 24"), + row(41, 42, 43, 24)) + assert_rows(executeFilteringOnly(cql, table, "SELECT * FROM %s WHERE b > 10 AND b < 25 AND cnt = 24"), + row(21, 22, 23, 24)) + assert_rows(executeFilteringOnly(cql, table, "SELECT * FROM %s WHERE b > 10 AND c < 25 AND cnt = 24"), + row(21, 22, 23, 24)) + + assertInvalidMessage(cql, table, + "ORDER BY is only supported when the partition key is restricted by an EQ or an IN.", + "SELECT * FROM %s WHERE a = 21 AND b > 10 AND cnt > 23 ORDER BY c DESC ALLOW FILTERING") + + assert_rows(executeFilteringOnly(cql, table, "SELECT * FROM %s WHERE a = 21 AND b = 22 AND cnt > 23 ORDER BY c DESC"), + row(21, 22, 26, 27), + row(21, 22, 23, 24)) + + assert_rows(executeFilteringOnly(cql, table, "SELECT * FROM %s WHERE cnt > 20 AND cnt < 30"), + row(41, 42, 43, 24), + row(21, 22, 23, 24), + row(21, 22, 26, 27)) + +@pytest.mark.xfail(reason="issue #12526") +def testAllowFilteringOnPartitionKeyOnCompactTablesWithoutIndicesAndWithLists(cql, test_keyspace): + # Test COMPACT table with clustering columns + with create_table(cql, test_keyspace, "(a int, b int, c frozen>, PRIMARY KEY (a, b)) WITH COMPACT STORAGE") as table: + execute(cql, table, "INSERT INTO %s (a, b, c) VALUES (1, 2, [4, 2])") + execute(cql, table, "INSERT INTO %s (a, b, c) VALUES (1, 3, [6, 2])") + execute(cql, table, "INSERT INTO %s (a, b, c) VALUES (1, 4, [4, 1])") + execute(cql, table, "INSERT INTO %s (a, b, c) VALUES (2, 3, [7, 1])") + + for _ in before_and_after_flush(cql, table): + # Checks filtering + assertInvalidMessage(cql, table, "filtering", + "SELECT * FROM %s WHERE a >= 1 AND b = 4 AND c = [4, 1]") + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE a >= 1 AND b >= 4 AND c = [4, 1] ALLOW FILTERING"), + row(1, 4, [4, 1])) + + assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + "SELECT * FROM %s WHERE a > 0 AND c > [4, 2]") + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE a >= 1 AND c > [4, 2] ALLOW FILTERING"), + row(1, 3, [6, 2]), + row(2, 3, [7, 1])) + + assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + "SELECT * FROM %s WHERE a > 1 AND b <= 3 AND c < [6, 2]") + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE a <= 1 AND b <= 3 AND c < [6, 2] ALLOW FILTERING"), + row(1, 2, [4, 2])) + + assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + "SELECT * FROM %s WHERE a <= 1 AND c >= [4, 2] AND c <= [6, 4]") + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE a > 0 AND b <= 3 AND c >= [4, 2] AND c <= [6, 4] ALLOW FILTERING"), + row(1, 2, [4, 2]), + row(1, 3, [6, 2])) + + assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + "SELECT * FROM %s WHERE a > 1 AND c CONTAINS 2") + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE a > 0 AND c CONTAINS 2 ALLOW FILTERING"), + row(1, 2, [4, 2]), + row(1, 3, [6, 2])) + + assertInvalidMessage(cql, table, "Cannot use CONTAINS KEY on non-map column c", + "SELECT * FROM %s WHERE a > 1 AND c CONTAINS KEY 2 ALLOW FILTERING") + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE a < 2 AND c CONTAINS 2 AND c CONTAINS 6 ALLOW FILTERING"), + row(1, 3, [6, 2])) + + # Checks filtering with null + assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + "SELECT * FROM %s WHERE a > 1 AND c = null") + assertInvalidMessage(cql, table, "Unsupported null value for column c", + "SELECT * FROM %s WHERE a > 1 AND c = null ALLOW FILTERING") + assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + "SELECT * FROM %s WHERE a > 1 AND c > null") + assertInvalidMessage(cql, table, "Unsupported null value for column c", + "SELECT * FROM %s WHERE a > 1 AND c > null ALLOW FILTERING") + assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + "SELECT * FROM %s WHERE a > 1 AND c CONTAINS null") + assertInvalidMessage(cql, table, "Unsupported null value for column c", + "SELECT * FROM %s WHERE a > 1 AND c CONTAINS null ALLOW FILTERING") + + # Checks filtering with unset + assertInvalidMessage(cql, table, "Unsupported unset value for column c", + "SELECT * FROM %s WHERE a > 1 AND c = ? ALLOW FILTERING", + unset()) + assertInvalidMessage(cql, table, "Unsupported unset value for column c", + "SELECT * FROM %s WHERE a > 1 AND c > ? ALLOW FILTERING", + unset()) + assertInvalidMessage(cql, table, "Unsupported unset value for column c", + "SELECT * FROM %s WHERE a > 1 AND c CONTAINS ? ALLOW FILTERING", + unset()) + + # Test COMPACT table without clustering columns + with create_table(cql, test_keyspace, "(a int PRIMARY KEY, b int, c frozen>) WITH COMPACT STORAGE") as table: + execute(cql, table, "INSERT INTO %s (a, b, c) VALUES (1, 2, [4, 2])") + execute(cql, table, "INSERT INTO %s (a, b, c) VALUES (2, 1, [6, 2])") + execute(cql, table, "INSERT INTO %s (a, b, c) VALUES (3, 2, [4, 1])") + execute(cql, table, "INSERT INTO %s (a, b, c) VALUES (4, 1, [7, 1])") + + for _ in before_and_after_flush(cql, table): + + # Checks filtering + assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + "SELECT * FROM %s WHERE a >= 1 AND b = 2 AND c = [4, 2]") + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE a >= 1 AND b = 2 AND c = [4, 2] ALLOW FILTERING"), + row(1, 2, [4, 2])) + + assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + "SELECT * FROM %s WHERE a > 1 AND c > [4, 2]") + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE a > 3 AND c > [4, 2] ALLOW FILTERING"), + row(4, 1, [7, 1])) + + assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + "SELECT * FROM %s WHERE a < 1 AND b < 3 AND c <= [4, 2]") + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE a < 3 AND b < 3 AND c <= [4, 2] ALLOW FILTERING"), + row(1, 2, [4, 2])) + + assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + "SELECT * FROM %s WHERE a > 1 AND c >= [4, 3] AND c <= [7]") + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE a >= 2 AND c >= [4, 3] AND c <= [7] ALLOW FILTERING"), + row(2, 1, [6, 2])) + + assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + "SELECT * FROM %s WHERE a > 3 AND c CONTAINS 2") + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE a >= 1 AND c CONTAINS 2 ALLOW FILTERING"), + row(1, 2, [4, 2]), + row(2, 1, [6, 2])) + + assertInvalidMessage(cql, table, "Cannot use CONTAINS KEY on non-map column c", + "SELECT * FROM %s WHERE a >=1 AND c CONTAINS KEY 2 ALLOW FILTERING") + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE a < 3 AND c CONTAINS 2 AND c CONTAINS 6 ALLOW FILTERING"), + row(2, 1, [6, 2])) + + # Checks filtering with null + assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + "SELECT * FROM %s WHERE a > 1 AND c = null") + assertInvalidMessage(cql, table, "Unsupported null value for column c", + "SELECT * FROM %s WHERE a > 1 AND c = null ALLOW FILTERING") + assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + "SELECT * FROM %s WHERE a > 1 AND c > null") + assertInvalidMessage(cql, table, "Unsupported null value for column c", + "SELECT * FROM %s WHERE a > 1 AND c > null ALLOW FILTERING") + assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + "SELECT * FROM %s WHERE a > 1 AND c CONTAINS null") + assertInvalidMessage(cql, table, "Unsupported null value for column c", + "SELECT * FROM %s WHERE a > 1 AND c CONTAINS null ALLOW FILTERING") + + # Checks filtering with unset + assertInvalidMessage(cql, table, "Unsupported unset value for column c", + "SELECT * FROM %s WHERE a > 1 AND c = ? ALLOW FILTERING", + unset()) + assertInvalidMessage(cql, table, "Unsupported unset value for column c", + "SELECT * FROM %s WHERE a > 1 AND c > ? ALLOW FILTERING", + unset()) + assertInvalidMessage(cql, table, "Unsupported unset value for column c", + "SELECT * FROM %s WHERE a > 1 AND c CONTAINS ? ALLOW FILTERING", + unset()) + + +@pytest.mark.xfail(reason="issue #12526") +def testAllowFilteringOnPartitionKeyOnCompactTablesWithoutIndicesAndWithMaps(cql, test_keyspace): + # Test COMPACT table with clustering columns + with create_table(cql, test_keyspace, "(a int, b int, c frozen>, PRIMARY KEY (a, b)) WITH COMPACT STORAGE") as table: + execute(cql, table, "INSERT INTO %s (a, b, c) VALUES (1, 2, {4 : 2})") + execute(cql, table, "INSERT INTO %s (a, b, c) VALUES (1, 3, {6 : 2})") + execute(cql, table, "INSERT INTO %s (a, b, c) VALUES (1, 4, {4 : 1})") + execute(cql, table, "INSERT INTO %s (a, b, c) VALUES (2, 3, {7 : 1})") + + for _ in before_and_after_flush(cql, table): + + # Checks filtering + assertInvalidMessage(cql, table, "filtering", + "SELECT * FROM %s WHERE a >= 1 AND b = 4 AND c = {4 : 1}") + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE a <= 1 AND b = 4 AND c = {4 : 1} ALLOW FILTERING"), + row(1, 4, {4: 1})) + + assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + "SELECT * FROM %s WHERE a > 1 AND c > {4 : 2}") + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE a > 1 AND c > {4 : 2} ALLOW FILTERING"), + row(2, 3, {7: 1})) + + assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + "SELECT * FROM %s WHERE a > 1 AND b <= 3 AND c < {6 : 2}") + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE a >= 1 AND b <= 3 AND c < {6 : 2} ALLOW FILTERING"), + row(1, 2, {4: 2})) + + assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + "SELECT * FROM %s WHERE a > 1 AND c >= {4 : 2} AND c <= {6 : 4}") + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE a > 0 AND c >= {4 : 2} AND c <= {6 : 4} ALLOW FILTERING"), + row(1, 2, {4: 2}), + row(1, 3, {6: 2})) + + assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + "SELECT * FROM %s WHERE a > 10 AND c CONTAINS 2") + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE a > 0 AND c CONTAINS 2 ALLOW FILTERING"), + row(1, 2, {4: 2}), + row(1, 3, {6: 2})) + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE a < 2 AND c CONTAINS KEY 6 ALLOW FILTERING"), + row(1, 3, {6: 2})) + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE a >= 1 AND c CONTAINS 2 AND c CONTAINS KEY 6 ALLOW FILTERING"), + row(1, 3, {6: 2})) + + # Checks filtering with null + assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + "SELECT * FROM %s WHERE a >= 1 AND c = null") + assertInvalidMessage(cql, table, "Unsupported null value for column c", + "SELECT * FROM %s WHERE a >= 1 AND c = null ALLOW FILTERING") + assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + "SELECT * FROM %s WHERE a >= 1 AND c > null") + assertInvalidMessage(cql, table, "Unsupported null value for column c", + "SELECT * FROM %s WHERE a >= 1 AND c > null ALLOW FILTERING") + assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + "SELECT * FROM %s WHERE a >= 1 AND c CONTAINS null") + assertInvalidMessage(cql, table, "Unsupported null value for column c", + "SELECT * FROM %s WHERE a >= 1 AND c CONTAINS null ALLOW FILTERING") + assertInvalidMessage(cql, table, "Unsupported null value for column c", + "SELECT * FROM %s WHERE a >= 1 AND c CONTAINS KEY null ALLOW FILTERING") + + # Checks filtering with unset + assertInvalidMessage(cql, table, "Unsupported unset value for column c", + "SELECT * FROM %s WHERE a >= 1 AND c = ? ALLOW FILTERING", + unset()) + assertInvalidMessage(cql, table, "Unsupported unset value for column c", + "SELECT * FROM %s WHERE a >= 1 AND c > ? ALLOW FILTERING", + unset()) + assertInvalidMessage(cql, table, "Unsupported unset value for column c", + "SELECT * FROM %s WHERE a >= 1 AND c CONTAINS ? ALLOW FILTERING", + unset()) + assertInvalidMessage(cql, table, "Unsupported unset value for column c", + "SELECT * FROM %s WHERE a >= 1 AND c CONTAINS KEY ? ALLOW FILTERING", + unset()) + + # Test COMPACT table without clustering columns + with create_table(cql, test_keyspace, "(a int PRIMARY KEY, b int, c frozen>) WITH COMPACT STORAGE") as table: + execute(cql, table, "INSERT INTO %s (a, b, c) VALUES (1, 2, {4 : 2})") + execute(cql, table, "INSERT INTO %s (a, b, c) VALUES (2, 1, {6 : 2})") + execute(cql, table, "INSERT INTO %s (a, b, c) VALUES (3, 2, {4 : 1})") + execute(cql, table, "INSERT INTO %s (a, b, c) VALUES (4, 1, {7 : 1})") + + for _ in before_and_after_flush(cql, table): + + # Checks filtering + assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + "SELECT * FROM %s WHERE a >= 1 AND b = 2 AND c = {4 : 2}") + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE a >= 1 AND b = 2 AND c = {4 : 2} ALLOW FILTERING"), + row(1, 2, {4: 2})) + + assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + "SELECT * FROM %s WHERE a >= 1 AND c > {4 : 2}") + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE a >= 1 AND c > {4 : 2} ALLOW FILTERING"), + row(2, 1, {6: 2}), + row(4, 1, {7: 1})) + + assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + "SELECT * FROM %s WHERE a >= 1 AND b < 3 AND c <= {4 : 2}") + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE a >= 1 AND b < 3 AND c <= {4 : 2} ALLOW FILTERING"), + row(1, 2, {4: 2}), + row(3, 2, {4: 1})) + + assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + "SELECT * FROM %s WHERE a >= 1 AND c >= {4 : 3} AND c <= {7 : 1}") + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE a >= 2 AND c >= {5 : 2} AND c <= {7 : 0} ALLOW FILTERING"), + row(2, 1, {6: 2})) + + assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + "SELECT * FROM %s WHERE a >= 1 AND c CONTAINS 2") + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE a >= 1 AND c CONTAINS 2 ALLOW FILTERING"), + row(1, 2, {4: 2}), + row(2, 1, {6: 2})) + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE a > 0 AND c CONTAINS KEY 4 ALLOW FILTERING"), + row(1, 2, {4: 2}), + row(3, 2, {4: 1})) + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE a >= 2 AND c CONTAINS 2 AND c CONTAINS KEY 6 ALLOW FILTERING"), + row(2, 1, {6: 2})) + + # Checks filtering with null + assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + "SELECT * FROM %s WHERE a >= 1 AND c = null") + assertInvalidMessage(cql, table, "Unsupported null value for column c", + "SELECT * FROM %s WHERE a >= 1 AND c = null ALLOW FILTERING") + assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + "SELECT * FROM %s WHERE a >= 1 AND c > null") + assertInvalidMessage(cql, table, "Unsupported null value for column c", + "SELECT * FROM %s WHERE a >= 1 AND c > null ALLOW FILTERING") + assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + "SELECT * FROM %s WHERE a >= 1 AND c CONTAINS null") + assertInvalidMessage(cql, table, "Unsupported null value for column c", + "SELECT * FROM %s WHERE a >= 1 AND c CONTAINS null ALLOW FILTERING") + assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + "SELECT * FROM %s WHERE a >= 1 AND c CONTAINS KEY null") + assertInvalidMessage(cql, table, "Unsupported null value for column c", + "SELECT * FROM %s WHERE a >= 1 AND c CONTAINS KEY null ALLOW FILTERING") + + # Checks filtering with unset + assertInvalidMessage(cql, table, "Unsupported unset value for column c", + "SELECT * FROM %s WHERE a >= 1 AND c = ? ALLOW FILTERING", + unset()) + assertInvalidMessage(cql, table, "Unsupported unset value for column c", + "SELECT * FROM %s WHERE a >= 1 AND c > ? ALLOW FILTERING", + unset()) + assertInvalidMessage(cql, table, "Unsupported unset value for column c", + "SELECT * FROM %s WHERE a >= 1 AND c CONTAINS ? ALLOW FILTERING", + unset()) + assertInvalidMessage(cql, table, "Unsupported unset value for column c", + "SELECT * FROM %s WHERE a >= 1 AND c CONTAINS KEY ? ALLOW FILTERING", + unset()) + +@pytest.mark.xfail(reason="issue #12526") +def testAllowFilteringOnPartitionKeyOnCompactTablesWithoutIndicesAndWithSets(cql, test_keyspace): + # Test COMPACT table with clustering columns + with create_table(cql, test_keyspace, "(a int, b int, c frozen>, PRIMARY KEY (a, b)) WITH COMPACT STORAGE") as table: + execute(cql, table, "INSERT INTO %s (a, b, c) VALUES (1, 2, {4, 2})") + execute(cql, table, "INSERT INTO %s (a, b, c) VALUES (1, 3, {6, 2})") + execute(cql, table, "INSERT INTO %s (a, b, c) VALUES (1, 4, {4, 1})") + execute(cql, table, "INSERT INTO %s (a, b, c) VALUES (2, 3, {7, 1})") + + for _ in before_and_after_flush(cql, table): + + # Checks filtering + assertInvalidMessage(cql, table, "filtering", + "SELECT * FROM %s WHERE a >= 1 AND b = 4 AND c = {4, 1}") + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE a >= 1 AND b = 4 AND c = {4, 1} ALLOW FILTERING"), + row(1, 4, {4, 1})) + + assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + "SELECT * FROM %s WHERE a >= 1 AND c > {4, 2}") + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE a >= 1 AND c > {4, 2} ALLOW FILTERING"), + row(1, 3, {6, 2})) + + assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + "SELECT * FROM %s WHERE a >= 1 AND b <= 3 AND c < {6, 2}") + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE a > 0 AND b <= 3 AND c < {6, 2} ALLOW FILTERING"), + row(1, 2, {2, 4}), + row(2, 3, {1, 7})) + + assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + "SELECT * FROM %s WHERE a >= 1 AND c >= {4, 2} AND c <= {6, 4}") + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE a >= 0 AND c >= {4, 2} AND c <= {6, 4} ALLOW FILTERING"), + row(1, 2, {4, 2}), + row(1, 3, {6, 2})) + + assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + "SELECT * FROM %s WHERE a >= 1 AND c CONTAINS 2") + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE a < 2 AND c CONTAINS 2 ALLOW FILTERING"), + row(1, 2, {4, 2}), + row(1, 3, {6, 2})) + + assertInvalidMessage(cql, table, "Cannot use CONTAINS KEY on non-map column c", + "SELECT * FROM %s WHERE a >= 1 AND c CONTAINS KEY 2 ALLOW FILTERING") + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE a >= 1 AND c CONTAINS 2 AND c CONTAINS 6 ALLOW FILTERING"), + row(1, 3, {6, 2})) + + # Checks filtering with null + assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + "SELECT * FROM %s WHERE a >= 1 AND c = null") + assertInvalidMessage(cql, table, "Unsupported null value for column c", + "SELECT * FROM %s WHERE a >= 1 AND c = null ALLOW FILTERING") + assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + "SELECT * FROM %s WHERE a >= 1 AND c > null") + assertInvalidMessage(cql, table, "Unsupported null value for column c", + "SELECT * FROM %s WHERE a >= 1 AND c > null ALLOW FILTERING") + assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + "SELECT * FROM %s WHERE a >= 1 AND c CONTAINS null") + assertInvalidMessage(cql, table, "Unsupported null value for column c", + "SELECT * FROM %s WHERE a >= 1 AND c CONTAINS null ALLOW FILTERING") + + # Checks filtering with unset + assertInvalidMessage(cql, table, "Unsupported unset value for column c", + "SELECT * FROM %s WHERE a >= 1 AND c = ? ALLOW FILTERING", + unset()) + assertInvalidMessage(cql, table, "Unsupported unset value for column c", + "SELECT * FROM %s WHERE a >= 1 AND c > ? ALLOW FILTERING", + unset()) + assertInvalidMessage(cql, table, "Unsupported unset value for column c", + "SELECT * FROM %s WHERE a >= 1 AND c CONTAINS ? ALLOW FILTERING", + unset()) + + # Test COMPACT table without clustering columns + with create_table(cql, test_keyspace, "(a int PRIMARY KEY, b int, c frozen>) WITH COMPACT STORAGE") as table: + execute(cql, table, "INSERT INTO %s (a, b, c) VALUES (1, 2, {4, 2})") + execute(cql, table, "INSERT INTO %s (a, b, c) VALUES (2, 1, {6, 2})") + execute(cql, table, "INSERT INTO %s (a, b, c) VALUES (3, 2, {4, 1})") + execute(cql, table, "INSERT INTO %s (a, b, c) VALUES (4, 1, {7, 1})") + + for _ in before_and_after_flush(cql, table): + + # Checks filtering + assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + "SELECT * FROM %s WHERE a >= 1 AND b = 2 AND c = {4, 2}") + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE a >= 1 AND b = 2 AND c = {4, 2} ALLOW FILTERING"), + row(1, 2, {4, 2})) + + assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + "SELECT * FROM %s WHERE a >= 1 AND c > {4, 2}") + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE a >= 1 AND c > {4, 2} ALLOW FILTERING"), + row(2, 1, {6, 2})) + + assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + "SELECT * FROM %s WHERE a >= 1 AND b < 3 AND c <= {4, 2}") + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE a <= 4 AND b < 3 AND c <= {4, 2} ALLOW FILTERING"), + row(1, 2, {4, 2}), + row(4, 1, {1, 7}), + row(3, 2, {4, 1})) + + assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + "SELECT * FROM %s WHERE a >= 1 AND c >= {4, 3} AND c <= {7}") + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE a < 3 AND c >= {5, 2} AND c <= {7} ALLOW FILTERING"), + row(2, 1, {6, 2})) + + assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + "SELECT * FROM %s WHERE a >= 1 AND c CONTAINS 2") + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE a >= 0 AND c CONTAINS 2 ALLOW FILTERING"), + row(1, 2, {4, 2}), + row(2, 1, {6, 2})) + + assertInvalidMessage(cql, table, "Cannot use CONTAINS KEY on non-map column c", + "SELECT * FROM %s WHERE a >= 1 AND c CONTAINS KEY 2 ALLOW FILTERING") + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE a >= 2 AND c CONTAINS 2 AND c CONTAINS 6 ALLOW FILTERING"), + row(2, 1, {6, 2})) + + # Checks filtering with null + assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + "SELECT * FROM %s WHERE a >= 1 AND c = null") + assertInvalidMessage(cql, table, "Unsupported null value for column c", + "SELECT * FROM %s WHERE a >= 1 AND c = null ALLOW FILTERING") + assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + "SELECT * FROM %s WHERE a >= 1 AND c > null") + assertInvalidMessage(cql, table, "Unsupported null value for column c", + "SELECT * FROM %s WHERE a >= 1 AND c > null ALLOW FILTERING") + assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + "SELECT * FROM %s WHERE a >= 1 AND c CONTAINS null") + assertInvalidMessage(cql, table, "Unsupported null value for column c", + "SELECT * FROM %s WHERE a >= 1 AND c CONTAINS null ALLOW FILTERING") + + # Checks filtering with unset + assertInvalidMessage(cql, table, "Unsupported unset value for column c", + "SELECT * FROM %s WHERE a >= 1 AND c = ? ALLOW FILTERING", + unset()) + assertInvalidMessage(cql, table, "Unsupported unset value for column c", + "SELECT * FROM %s WHERE a >= 1 AND c > ? ALLOW FILTERING", + unset()) + assertInvalidMessage(cql, table, "Unsupported unset value for column c", + "SELECT * FROM %s WHERE a >= 1 AND c CONTAINS ? ALLOW FILTERING", + unset()) + +@pytest.mark.xfail(reason="issue #12526") +def testAllowFilteringOnPartitionKeyOnCompactTablesWithoutIndices(cql, test_keyspace): + # Test COMPACT table with clustering columns + with create_table(cql, test_keyspace, "(a int, b int, c int, d int, PRIMARY KEY ((a, b), c)) WITH COMPACT STORAGE") as table: + execute(cql, table, "INSERT INTO %s (a, b, c, d) VALUES (1, 2, 4, 5)") + execute(cql, table, "INSERT INTO %s (a, b, c, d) VALUES (1, 3, 6, 7)") + execute(cql, table, "INSERT INTO %s (a, b, c, d) VALUES (1, 4, 4, 5)") + execute(cql, table, "INSERT INTO %s (a, b, c, d) VALUES (2, 3, 7, 8)") + + # Adds tomstones + execute(cql, table, "INSERT INTO %s (a, b, c, d) VALUES (1, 1, 4, 5)") + execute(cql, table, "INSERT INTO %s (a, b, c, d) VALUES (2, 2, 7, 8)") + execute(cql, table, "DELETE FROM %s WHERE a = 1 AND b = 1 AND c = 4") + execute(cql, table, "DELETE FROM %s WHERE a = 2 AND b = 2 AND c = 7") + + for _ in before_and_after_flush(cql, table): + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE a = 1 AND b = 4 AND c = 4"), + row(1, 4, 4, 5)) + + # Checks filtering + assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + "SELECT * FROM %s WHERE a = 1 AND b = 4 AND c = 4 AND d = 5") + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE a = 1 AND b = 4 AND c = 4 ALLOW FILTERING"), + row(1, 4, 4, 5)) + + assertInvalidMessage(cql, table, "IN predicates on non-primary-key columns (d) is not yet supported", + "SELECT * FROM %s WHERE a IN (1, 2) AND b = 3 AND d IN (6, 7)") + + assertInvalidMessage(cql, table, "IN predicates on non-primary-key columns (d) is not yet supported", + "SELECT * FROM %s WHERE a IN (1, 2) AND b = 3 AND d IN (6, 7) ALLOW FILTERING") + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE a < 2 AND c > 4 AND c <= 6 ALLOW FILTERING"), + row(1, 3, 6, 7)) + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE a <= 1 AND b >= 2 AND c >= 4 AND d <= 8 ALLOW FILTERING"), + row(1, 3, 6, 7), + row(1, 4, 4, 5), + row(1, 2, 4, 5)) + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE a = 1 AND c >= 4 AND d <= 8 ALLOW FILTERING"), + row(1, 3, 6, 7), + row(1, 4, 4, 5), + row(1, 2, 4, 5)) + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE a >= 2 AND c >= 4 AND d <= 8 ALLOW FILTERING"), + row(2, 3, 7, 8)) + + # Checks filtering with null + assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + "SELECT * FROM %s WHERE d = null") + assertInvalidMessage(cql, table, "Unsupported null value for column a", + "SELECT * FROM %s WHERE a = null ALLOW FILTERING") + assertInvalidMessage(cql, table, "Unsupported null value for column a", + "SELECT * FROM %s WHERE a > null ALLOW FILTERING") + + # Checks filtering with unset + assertInvalidMessage(cql, table, "Unsupported unset value for column a", + "SELECT * FROM %s WHERE a = ? ALLOW FILTERING", + unset()) + assertInvalidMessage(cql, table, "Unsupported unset value for column a", + "SELECT * FROM %s WHERE a > ? ALLOW FILTERING", + unset()) + + # Test COMPACT table without clustering columns + with create_table(cql, test_keyspace, "(a int primary key, b int, c int) WITH COMPACT STORAGE") as table: + execute(cql, table, "INSERT INTO %s (a, b, c) VALUES (1, 2, 4)") + execute(cql, table, "INSERT INTO %s (a, b, c) VALUES (2, 1, 6)") + execute(cql, table, "INSERT INTO %s (a, b, c) VALUES (3, 2, 4)") + execute(cql, table, "INSERT INTO %s (a, b, c) VALUES (4, 1, 7)") + + # Adds tomstones + execute(cql, table, "INSERT INTO %s (a, b, c) VALUES (0, 1, 4)") + execute(cql, table, "INSERT INTO %s (a, b, c) VALUES (5, 2, 7)") + execute(cql, table, "DELETE FROM %s WHERE a = 0") + execute(cql, table, "DELETE FROM %s WHERE a = 5") + + for _ in before_and_after_flush(cql, table): + # Checks filtering + assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + "SELECT * FROM %s WHERE a = 1 AND b = 4 AND c = 4") + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE a = 1 AND b = 2 AND c = 4 ALLOW FILTERING"), + row(1, 2, 4)) + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE a = 1 AND b = 2 ALLOW FILTERING"), + row(1, 2, 4)) + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE b >= 2 AND c <= 4 ALLOW FILTERING"), + row(1, 2, 4), + row(3, 2, 4)) + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE a = 1 ALLOW FILTERING"), + row(1, 2, 4)) + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE b >= 2 ALLOW FILTERING"), + row(1, 2, 4), + row(3, 2, 4)) + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE a >= 2 AND b <=1 ALLOW FILTERING"), + row(2, 1, 6), + row(4, 1, 7)) + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE a = 1 AND c >= 4 ALLOW FILTERING"), + row(1, 2, 4)) + + assertInvalidMessage(cql, table, "IN predicates on non-primary-key columns (b) is not yet supported", + "SELECT * FROM %s WHERE a = 1 AND b IN (1, 2) AND c IN (6, 7)") + + assertInvalidMessage(cql, table, "IN predicates on non-primary-key columns (c) is not yet supported", + "SELECT * FROM %s WHERE a IN (1, 2) AND c IN (6, 7) ALLOW FILTERING") + + assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + "SELECT * FROM %s WHERE c > 4") + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE c > 4 ALLOW FILTERING"), + row(2, 1, 6), + row(4, 1, 7)) + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE a >= 1 AND b >= 2 AND c <= 4 ALLOW FILTERING"), + row(1, 2, 4), + row(3, 2, 4)) + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE a < 3 AND c <= 4 ALLOW FILTERING"), + row(1, 2, 4)) + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE a < 3 AND b >= 2 AND c <= 4 ALLOW FILTERING"), + row(1, 2, 4)) + + assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + "SELECT * FROM %s WHERE c >= 3 AND c <= 6") + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE c <=6 ALLOW FILTERING"), + row(1, 2, 4), + row(2, 1, 6), + row(3, 2, 4)) + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE token(a) >= token(2)"), + row(2, 1, 6), + row(4, 1, 7), + row(3, 2, 4)) + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE token(a) >= token(2) ALLOW FILTERING"), + row(2, 1, 6), + row(4, 1, 7), + row(3, 2, 4)) + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE token(a) >= token(2) AND b = 1 ALLOW FILTERING"), + row(2, 1, 6), + row(4, 1, 7)) + +def testFilteringOnCompactTablesWithoutIndicesAndWithMaps(cql, test_keyspace): + # Test COMPACT table with clustering columns + with create_table(cql, test_keyspace, "(a int, b int, c frozen>, PRIMARY KEY ((a, b))) WITH COMPACT STORAGE") as table: + execute(cql, table, "INSERT INTO %s (a, b, c) VALUES (1, 2, {4 : 2})") + execute(cql, table, "INSERT INTO %s (a, b, c) VALUES (1, 3, {6 : 2})") + execute(cql, table, "INSERT INTO %s (a, b, c) VALUES (1, 4, {4 : 1})") + execute(cql, table, "INSERT INTO %s (a, b, c) VALUES (2, 3, {7 : 1})") + + for _ in before_and_after_flush(cql, table): + + # Checks filtering + assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + "SELECT * FROM %s WHERE a = 1 AND b = 4 AND c = {4 : 1}") + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE a = 1 AND b = 4 AND c = {4 : 1} ALLOW FILTERING"), + row(1, 4, {4: 1})) + + assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + "SELECT * FROM %s WHERE c > {4 : 2}") + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE c > {4 : 2} ALLOW FILTERING"), + row(1, 3, {6: 2}), + row(2, 3, {7: 1})) + + assertInvalidMessage(cql, table, 'filtering', + "SELECT * FROM %s WHERE b <= 3 AND c < {6 : 2}") + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE b <= 3 AND c < {6 : 2} ALLOW FILTERING"), + row(1, 2, {4: 2})) + + assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + "SELECT * FROM %s WHERE c >= {4 : 2} AND c <= {6 : 4}") + + assert_rows_ignoring_order(execute(cql, table, "SELECT * FROM %s WHERE c >= {4 : 2} AND c <= {6 : 4} ALLOW FILTERING"), + row(1, 2, {4: 2}), + row(1, 3, {6: 2})) + + assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + "SELECT * FROM %s WHERE c CONTAINS 2") + + assert_rows_ignoring_order(execute(cql, table, "SELECT * FROM %s WHERE c CONTAINS 2 ALLOW FILTERING"), + row(1, 2, {4: 2}), + row(1, 3, {6: 2})) + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE c CONTAINS KEY 6 ALLOW FILTERING"), + row(1, 3, {6: 2})) + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE c CONTAINS 2 AND c CONTAINS KEY 6 ALLOW FILTERING"), + row(1, 3, {6: 2})) + + # Checks filtering with null + # tests commented out because Scylla does support comparison with null + # (returning nothing) + #assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + # "SELECT * FROM %s WHERE c = null") + #assertInvalidMessage(cql, table, "Unsupported null value for column c", + # "SELECT * FROM %s WHERE c = null ALLOW FILTERING") + #assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + # "SELECT * FROM %s WHERE c > null") + #assertInvalidMessage(cql, table, "Unsupported null value for column c", + # "SELECT * FROM %s WHERE c > null ALLOW FILTERING") + #assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + # "SELECT * FROM %s WHERE c CONTAINS null") + #assertInvalidMessage(cql, table, "Unsupported null value for column c", + # "SELECT * FROM %s WHERE c CONTAINS null ALLOW FILTERING") + #assertInvalidMessage(cql, table, "Unsupported null value for column c", + # "SELECT * FROM %s WHERE c CONTAINS KEY null ALLOW FILTERING") + + # Checks filtering with unset + assertInvalidMessage(cql, table, "unset", + "SELECT * FROM %s WHERE c = ? ALLOW FILTERING", + unset()) + assertInvalidMessage(cql, table, "unset", + "SELECT * FROM %s WHERE c > ? ALLOW FILTERING", + unset()) + assertInvalidMessage(cql, table, "unset", + "SELECT * FROM %s WHERE c CONTAINS ? ALLOW FILTERING", + unset()) + assertInvalidMessage(cql, table, "unset", + "SELECT * FROM %s WHERE c CONTAINS KEY ? ALLOW FILTERING", + unset()) + + # Test COMPACT table without clustering columns + with create_table(cql, test_keyspace, "(a int PRIMARY KEY, b int, c frozen>) WITH COMPACT STORAGE") as table: + + execute(cql, table, "INSERT INTO %s (a, b, c) VALUES (1, 2, {4 : 2})") + execute(cql, table, "INSERT INTO %s (a, b, c) VALUES (2, 1, {6 : 2})") + execute(cql, table, "INSERT INTO %s (a, b, c) VALUES (3, 2, {4 : 1})") + execute(cql, table, "INSERT INTO %s (a, b, c) VALUES (4, 1, {7 : 1})") + + for _ in before_and_after_flush(cql, table): + + # Checks filtering + assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + "SELECT * FROM %s WHERE a = 1 AND b = 2 AND c = {4 : 2}") + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE a = 1 AND b = 2 AND c = {4 : 2} ALLOW FILTERING"), + row(1, 2, {4: 2})) + + assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + "SELECT * FROM %s WHERE c > {4 : 2}") + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE c > {4 : 2} ALLOW FILTERING"), + row(2, 1, {6: 2}), + row(4, 1, {7: 1})) + + assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + "SELECT * FROM %s WHERE b < 3 AND c <= {4 : 2}") + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE b < 3 AND c <= {4 : 2} ALLOW FILTERING"), + row(1, 2, {4: 2}), + row(3, 2, {4: 1})) + + assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + "SELECT * FROM %s WHERE c >= {4 : 3} AND c <= {7 : 1}") + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE c >= {5 : 2} AND c <= {7 : 0} ALLOW FILTERING"), + row(2, 1, {6: 2})) + + assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + "SELECT * FROM %s WHERE c CONTAINS 2") + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE c CONTAINS 2 ALLOW FILTERING"), + row(1, 2, {4: 2}), + row(2, 1, {6: 2})) + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE c CONTAINS KEY 4 ALLOW FILTERING"), + row(1, 2, {4: 2}), + row(3, 2, {4: 1})) + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE c CONTAINS 2 AND c CONTAINS KEY 6 ALLOW FILTERING"), + row(2, 1, {6: 2})) + + # Checks filtering with null + # Checks filtering with null + # tests commented out because Scylla does support comparison with null + # (returning nothing) + #assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + # "SELECT * FROM %s WHERE c = null") + #assertInvalidMessage(cql, table, "Unsupported null value for column c", + # "SELECT * FROM %s WHERE c = null ALLOW FILTERING") + #assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + # "SELECT * FROM %s WHERE c > null") + #assertInvalidMessage(cql, table, "Unsupported null value for column c", + # "SELECT * FROM %s WHERE c > null ALLOW FILTERING") + #assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + # "SELECT * FROM %s WHERE c CONTAINS null") + #assertInvalidMessage(cql, table, "Unsupported null value for column c", + # "SELECT * FROM %s WHERE c CONTAINS null ALLOW FILTERING") + #assertInvalidMessage(cql, table, REQUIRES_ALLOW_FILTERING_MESSAGE, + # "SELECT * FROM %s WHERE c CONTAINS KEY null") + #assertInvalidMessage(cql, table, "Unsupported null value for column c", + # "SELECT * FROM %s WHERE c CONTAINS KEY null ALLOW FILTERING") + + # Checks filtering with unset + assertInvalidMessage(cql, table, "unset", + "SELECT * FROM %s WHERE c = ? ALLOW FILTERING", + unset()) + assertInvalidMessage(cql, table, "unset", + "SELECT * FROM %s WHERE c > ? ALLOW FILTERING", + unset()) + assertInvalidMessage(cql, table, "unset", + "SELECT * FROM %s WHERE c CONTAINS ? ALLOW FILTERING", + unset()) + assertInvalidMessage(cql, table, "unset", + "SELECT * FROM %s WHERE c CONTAINS KEY ? ALLOW FILTERING", + unset()) + +@pytest.mark.xfail(reason="issue #12526") +def testFilteringOnCompactTable(cql, test_keyspace): + with create_table(cql, test_keyspace, "(a int, b int, c int, d int, PRIMARY KEY (a, b, c)) WITH COMPACT STORAGE") as table: + execute(cql, table, "INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 11, 12, 13, 14) + execute(cql, table, "INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 21, 22, 23, 24) + execute(cql, table, "INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 21, 25, 26, 27) + execute(cql, table, "INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 31, 32, 33, 34) + + for _ in before_and_after_flush(cql, table): + assert_rows(executeFilteringOnly(cql, table, "SELECT * FROM %s WHERE c > 13"), + row(21, 22, 23, 24), + row(21, 25, 26, 27), + row(31, 32, 33, 34)) + + assert_rows(executeFilteringOnly(cql, table, "SELECT * FROM %s WHERE c > 13 AND c < 33"), + row(21, 22, 23, 24), + row(21, 25, 26, 27)) + + assert_rows(executeFilteringOnly(cql, table, "SELECT * FROM %s WHERE c > 13 AND b < 32"), + row(21, 22, 23, 24), + row(21, 25, 26, 27)) + + assert_rows(executeFilteringOnly(cql, table, "SELECT * FROM %s WHERE a = 21 AND c > 13 AND b < 32 ORDER BY b DESC"), + row(21, 25, 26, 27), + row(21, 22, 23, 24)) + + # (NYH: note that because the partition order isn't known, we can't + # actually check the result order here, hence I added ignoring_order. + # this makes this test weaker). + assert_rows_ignoring_order(executeFilteringOnly(cql, table, "SELECT * FROM %s WHERE a IN (21, 31) AND c > 13 ORDER BY b DESC"), + row(31, 32, 33, 34), + row(21, 25, 26, 27), + row(21, 22, 23, 24)) + + # Reproduces #12526: + assert_rows(executeFilteringOnly(cql, table, "SELECT * FROM %s WHERE c > 13 AND d < 34"), + row(21, 22, 23, 24), + row(21, 25, 26, 27)) + + assert_rows(executeFilteringOnly(cql, table, "SELECT * FROM %s WHERE c > 13"), + row(21, 22, 23, 24), + row(21, 25, 26, 27), + row(31, 32, 33, 34)) + + # with frozen in clustering key + with create_table(cql, test_keyspace, "(a int, b int, c frozen>, d int, PRIMARY KEY (a, b, c)) WITH COMPACT STORAGE") as table: + execute(cql, table, "INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 11, 12, [1, 3], 14) + execute(cql, table, "INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 21, 22, [2, 3], 24) + execute(cql, table, "INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 21, 25, [2, 6], 27) + execute(cql, table, "INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 31, 32, [3, 3], 34) + + for _ in before_and_after_flush(cql, table): + assert_rows(executeFilteringOnly(cql, table, "SELECT * FROM %s WHERE c CONTAINS 2"), + row(21, 22, [2, 3], 24), + row(21, 25, [2, 6], 27)) + + assert_rows(executeFilteringOnly(cql, table, "SELECT * FROM %s WHERE c CONTAINS 2 AND b < 25"), + row(21, 22, [2, 3], 24)) + + assert_rows(executeFilteringOnly(cql, table, "SELECT * FROM %s WHERE c CONTAINS 2 AND c CONTAINS 3"), + row(21, 22, [2, 3], 24)) + + # Reproduces #12526: + assert_rows(executeFilteringOnly(cql, table, "SELECT * FROM %s WHERE b > 12 AND c CONTAINS 2 AND d < 27"), + row(21, 22, [2, 3], 24)) + + # with frozen in value + with create_table(cql, test_keyspace, "(a int, b int, c int, d frozen>, PRIMARY KEY (a, b, c)) WITH COMPACT STORAGE") as table: + execute(cql, table, "INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 11, 12, 13, [1, 4]) + execute(cql, table, "INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 21, 22, 23, [2, 4]) + execute(cql, table, "INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 21, 25, 25, [2, 6]) + execute(cql, table, "INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 31, 32, 34, [3, 4]) + + for _ in before_and_after_flush(cql, table): + # Reproduces #12526: + assert_rows(executeFilteringOnly(cql, table, "SELECT * FROM %s WHERE d CONTAINS 2"), + row(21, 22, 23, [2, 4]), + row(21, 25, 25, [2, 6])) + + assert_rows(executeFilteringOnly(cql, table, "SELECT * FROM %s WHERE d CONTAINS 2 AND b < 25"), + row(21, 22, 23, [2, 4])) + + assert_rows(executeFilteringOnly(cql, table, "SELECT * FROM %s WHERE d CONTAINS 2 AND d CONTAINS 4"), + row(21, 22, 23, [2, 4])) + + assert_rows(executeFilteringOnly(cql, table, "SELECT * FROM %s WHERE b > 12 AND c < 25 AND d CONTAINS 2"), + row(21, 22, 23, [2, 4])) + +@pytest.mark.xfail(reason="issue #12526") +def testFilteringWithCounters(cql, test_keyspace): + with create_table(cql, test_keyspace, "(a int, b int, c int, cnt counter, PRIMARY KEY (a, b, c)) WITH COMPACT STORAGE") as table: + execute(cql, table, "UPDATE %s SET cnt = cnt + ? WHERE a = ? AND b = ? AND c = ?", 14, 11, 12, 13) + execute(cql, table, "UPDATE %s SET cnt = cnt + ? WHERE a = ? AND b = ? AND c = ?", 24, 21, 22, 23) + execute(cql, table, "UPDATE %s SET cnt = cnt + ? WHERE a = ? AND b = ? AND c = ?", 27, 21, 25, 26) + execute(cql, table, "UPDATE %s SET cnt = cnt + ? WHERE a = ? AND b = ? AND c = ?", 34, 31, 32, 33) + execute(cql, table, "UPDATE %s SET cnt = cnt + ? WHERE a = ? AND b = ? AND c = ?", 24, 41, 42, 43) + + for _ in before_and_after_flush(cql, table): + + assert_rows(executeFilteringOnly(cql, table, "SELECT * FROM %s WHERE cnt = 24"), + row(21, 22, 23, 24), + row(41, 42, 43, 24)) + assert_rows(executeFilteringOnly(cql, table, "SELECT * FROM %s WHERE b > 22 AND cnt = 24"), + row(41, 42, 43, 24)) + assert_rows(executeFilteringOnly(cql, table, "SELECT * FROM %s WHERE b > 10 AND b < 25 AND cnt = 24"), + row(21, 22, 23, 24)) + assert_rows(executeFilteringOnly(cql, table, "SELECT * FROM %s WHERE b > 10 AND c < 25 AND cnt = 24"), + row(21, 22, 23, 24)) + assert_rows(executeFilteringOnly(cql, table, "SELECT * FROM %s WHERE a = 21 AND b > 10 AND cnt > 23 ORDER BY b DESC"), + row(21, 25, 26, 27), + row(21, 22, 23, 24)) + assert_rows(executeFilteringOnly(cql, table, "SELECT * FROM %s WHERE cnt > 20 AND cnt < 30"), + row(21, 22, 23, 24), + row(21, 25, 26, 27), + row(41, 42, 43, 24)) + +# Check select with and without compact storage, with different column +# order. See CASSANDRA-10988 +def testClusteringOrderWithSlice(cql, test_keyspace): + # non-compound, ASC order + with create_table(cql, test_keyspace, "(a text, b int, PRIMARY KEY (a, b)) WITH COMPACT STORAGE AND CLUSTERING ORDER BY (b ASC)") as table: + execute(cql, table, "INSERT INTO %s (a, b) VALUES ('a', 2)") + execute(cql, table, "INSERT INTO %s (a, b) VALUES ('a', 3)") + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE a = 'a' AND b > 0"), + row("a", 2), + row("a", 3)) + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE a = 'a' AND b > 0 ORDER BY b DESC"), + row("a", 3), + row("a", 2)) + + # non-compound, DESC order + with create_table(cql, test_keyspace, "(a text, b int, PRIMARY KEY (a, b)) WITH COMPACT STORAGE AND CLUSTERING ORDER BY (b DESC)") as table: + execute(cql, table, "INSERT INTO %s (a, b) VALUES ('a', 2)") + execute(cql, table, "INSERT INTO %s (a, b) VALUES ('a', 3)") + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE a = 'a' AND b > 0"), + row("a", 3), + row("a", 2)) + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE a = 'a' AND b > 0 ORDER BY b ASC"), + row("a", 2), + row("a", 3)) + + # compound, first column DESC order + with create_table(cql, test_keyspace, "(a text, b int, c int, PRIMARY KEY (a, b, c)) WITH COMPACT STORAGE AND CLUSTERING ORDER BY (b DESC)") as table: + execute(cql, table, "INSERT INTO %s (a, b, c) VALUES ('a', 2, 4)") + execute(cql, table, "INSERT INTO %s (a, b, c) VALUES ('a', 3, 5)") + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE a = 'a' AND b > 0"), + row("a", 3, 5), + row("a", 2, 4)) + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE a = 'a' AND b > 0 ORDER BY b ASC"), + row("a", 2, 4), + row("a", 3, 5)) + + # compound, mixed order + with create_table(cql, test_keyspace, "(a text, b int, c int, PRIMARY KEY (a, b, c)) WITH COMPACT STORAGE AND CLUSTERING ORDER BY (b ASC, c DESC)") as table: + execute(cql, table, "INSERT INTO %s (a, b, c) VALUES ('a', 2, 4)") + execute(cql, table, "INSERT INTO %s (a, b, c) VALUES ('a', 3, 5)") + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE a = 'a' AND b > 0"), + row("a", 2, 4), + row("a", 3, 5)) + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE a = 'a' AND b > 0 ORDER BY b ASC"), + row("a", 2, 4), + row("a", 3, 5)) + +EMPTY_BYTE_BUFFER = b"" + +@pytest.mark.parametrize("options", ["", pytest.param(" WITH COMPACT STORAGE", marks=pytest.mark.xfail(reason="issue #12526, #12749"))]) +def testEmptyRestrictionValue(cql, test_keyspace, options): + with create_table(cql, test_keyspace, "(pk blob, c blob, v blob, PRIMARY KEY ((pk), c))" + options) as table: + execute(cql, table, "INSERT INTO %s (pk, c, v) VALUES (?, ?, ?)", + b"foo123", b"1", b"1") + execute(cql, table, "INSERT INTO %s (pk, c, v) VALUES (?, ?, ?)", + b"foo123", b"2", b"2") + + for _ in before_and_after_flush(cql, table): + # Scylla *does* allow lookup of an empty partition key (see + # test_mv_empty_string_partition_key_individual()), so we + # comment out this check + #assertInvalidMessage(cql, table, "Key may not be empty", "SELECT * FROM %s WHERE pk = textAsBlob('');") + #assertInvalidMessage(cql, table, "Key may not be empty", "SELECT * FROM %s WHERE pk IN (textAsBlob(''), textAsBlob('1'));") + + assertInvalidMessage(cql, table, "Key may not be empty", + "INSERT INTO %s (pk, c, v) VALUES (?, ?, ?)", + EMPTY_BYTE_BUFFER, b"2", b"2") + + # Test clustering columns restrictions + assertEmpty(execute(cql, table, "SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND c = textAsBlob('');")) + + assertEmpty(execute(cql, table, "SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND (c) = (textAsBlob(''));")) + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND c IN (textAsBlob(''), textAsBlob('1'));"), + row(b"foo123", b"1", b"1")) + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND (c) IN ((textAsBlob('')), (textAsBlob('1')));"), + row(b"foo123", b"1", b"1")) + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND c > textAsBlob('');"), + row(b"foo123", b"1", b"1"), + row(b"foo123", b"2", b"2")) + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND (c) > (textAsBlob(''));"), + row(b"foo123", b"1", b"1"), + row(b"foo123", b"2", b"2")) + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND c >= textAsBlob('');"), + row(b"foo123", b"1", b"1"), + row(b"foo123", b"2", b"2")) + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND (c) >= (textAsBlob(''));"), + row(b"foo123", b"1", b"1"), + row(b"foo123", b"2", b"2")) + + assertEmpty(execute(cql, table, "SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND c <= textAsBlob('');")) + + assertEmpty(execute(cql, table, "SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND (c) <= (textAsBlob(''));")) + + assertEmpty(execute(cql, table, "SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND c < textAsBlob('');")) + + assertEmpty(execute(cql, table, "SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND (c) < (textAsBlob(''));")) + + assertEmpty(execute(cql, table, "SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND c > textAsBlob('') AND c < textAsBlob('');")) + + if "COMPACT" in options: + # Reproduces #12749 + assertInvalidMessage(cql, table, "Invalid empty or null value for column c", + "INSERT INTO %s (pk, c, v) VALUES (?, ?, ?)", + b"foo123", EMPTY_BYTE_BUFFER, b"4") + else: + execute(cql, table, "INSERT INTO %s (pk, c, v) VALUES (?, ?, ?)", + b"foo123", EMPTY_BYTE_BUFFER, b"4") + + for _ in before_and_after_flush(cql, table): + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND c = textAsBlob('');"), + row(b"foo123", EMPTY_BYTE_BUFFER, b"4")) + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND (c) = (textAsBlob(''));"), + row(b"foo123", EMPTY_BYTE_BUFFER, b"4")) + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND c IN (textAsBlob(''), textAsBlob('1'));"), + row(b"foo123", EMPTY_BYTE_BUFFER, b"4"), + row(b"foo123", b"1", b"1")) + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND (c) IN ((textAsBlob('')), (textAsBlob('1')));"), + row(b"foo123", EMPTY_BYTE_BUFFER, b"4"), + row(b"foo123", b"1", b"1")) + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND c > textAsBlob('');"), + row(b"foo123", b"1", b"1"), + row(b"foo123", b"2", b"2")) + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND (c) > (textAsBlob(''));"), + row(b"foo123", b"1", b"1"), + row(b"foo123", b"2", b"2")) + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND c >= textAsBlob('');"), + row(b"foo123", EMPTY_BYTE_BUFFER, b"4"), + row(b"foo123", b"1", b"1"), + row(b"foo123", b"2", b"2")) + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND (c) >= (textAsBlob(''));"), + row(b"foo123", EMPTY_BYTE_BUFFER, b"4"), + row(b"foo123", b"1", b"1"), + row(b"foo123", b"2", b"2")) + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND c <= textAsBlob('');"), + row(b"foo123", EMPTY_BYTE_BUFFER, b"4")) + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND (c) <= (textAsBlob(''));"), + row(b"foo123", EMPTY_BYTE_BUFFER, b"4")) + + assertEmpty(execute(cql, table, "SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND c < textAsBlob('');")) + + assertEmpty(execute(cql, table, "SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND (c) < (textAsBlob(''));")) + + assertEmpty(execute(cql, table, "SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND c >= textAsBlob('') AND c < textAsBlob('');")) + # Test restrictions on non-primary key value + # Reproduces #12526: + assertEmpty(execute(cql, table, "SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND v = textAsBlob('') ALLOW FILTERING;")) + + execute(cql, table, "INSERT INTO %s (pk, c, v) VALUES (?, ?, ?)", + b"foo123", b"3", EMPTY_BYTE_BUFFER) + + for _ in before_and_after_flush(cql, table): + # Reproduces #12526: + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND v = textAsBlob('') ALLOW FILTERING;"), + row(b"foo123", b"3", EMPTY_BYTE_BUFFER)) + +@pytest.mark.xfail(reason="issue #12749") +def testEmptyRestrictionValueWithMultipleClusteringColumns(cql, test_keyspace): + with create_table(cql, test_keyspace, "(pk blob, c1 blob, c2 blob, v blob, PRIMARY KEY (pk, c1, c2)) WITH COMPACT STORAGE") as table: + execute(cql, table, "INSERT INTO %s (pk, c1, c2, v) VALUES (?, ?, ?, ?)", b"foo123", b"1", b"1", b"1") + execute(cql, table, "INSERT INTO %s (pk, c1, c2, v) VALUES (?, ?, ?, ?)", b"foo123", b"1", b"2", b"2") + + for _ in before_and_after_flush(cql, table): + assertEmpty(execute(cql, table, "SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND c1 = textAsBlob('');")) + + assertEmpty(execute(cql, table, "SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND c1 = textAsBlob('1') AND c2 = textAsBlob('');")) + + assertEmpty(execute(cql, table, "SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND (c1, c2) = (textAsBlob('1'), textAsBlob(''));")) + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND c1 IN (textAsBlob(''), textAsBlob('1')) AND c2 = textAsBlob('1');"), + row(b"foo123", b"1", b"1", b"1")) + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND c1 = textAsBlob('1') AND c2 IN (textAsBlob(''), textAsBlob('1'));"), + row(b"foo123", b"1", b"1", b"1")) + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND (c1, c2) IN ((textAsBlob(''), textAsBlob('1')), (textAsBlob('1'), textAsBlob('1')));"), + row(b"foo123", b"1", b"1", b"1")) + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND c1 > textAsBlob('');"), + row(b"foo123", b"1", b"1", b"1"), + row(b"foo123", b"1", b"2", b"2")) + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND c1 = textAsBlob('1') AND c2 > textAsBlob('');"), + row(b"foo123", b"1", b"1", b"1"), + row(b"foo123", b"1", b"2", b"2")) + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND (c1, c2) > (textAsBlob(''), textAsBlob('1'));"), + row(b"foo123", b"1", b"1", b"1"), + row(b"foo123", b"1", b"2", b"2")) + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND c1 = textAsBlob('1') AND c2 >= textAsBlob('');"), + row(b"foo123", b"1", b"1", b"1"), + row(b"foo123", b"1", b"2", b"2")) + + assertEmpty(execute(cql, table, "SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND c1 = textAsBlob('1') AND c2 <= textAsBlob('');")) + + assertEmpty(execute(cql, table, "SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND (c1, c2) <= (textAsBlob('1'), textAsBlob(''));")) + + # Reproduces #12749: + execute(cql, table, "INSERT INTO %s (pk, c1, c2, v) VALUES (?, ?, ?, ?)", + b"foo123", EMPTY_BYTE_BUFFER, b"1", b"4") + + for _ in before_and_after_flush(cql, table): + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND c1 = textAsBlob('');"), + row(b"foo123", EMPTY_BYTE_BUFFER, b"1", b"4")) + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND c1 = textAsBlob('') AND c2 = textAsBlob('1');"), + row(b"foo123", EMPTY_BYTE_BUFFER, b"1", b"4")) + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND (c1, c2) = (textAsBlob(''), textAsBlob('1'));"), + row(b"foo123", EMPTY_BYTE_BUFFER, b"1", b"4")) + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND c1 IN (textAsBlob(''), textAsBlob('1')) AND c2 = textAsBlob('1');"), + row(b"foo123", EMPTY_BYTE_BUFFER, b"1", b"4"), + row(b"foo123", b"1", b"1", b"1")) + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND (c1, c2) IN ((textAsBlob(''), textAsBlob('1')), (textAsBlob('1'), textAsBlob('1')));"), + row(b"foo123", EMPTY_BYTE_BUFFER, b"1", b"4"), + row(b"foo123", b"1", b"1", b"1")) + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND (c1, c2) > (textAsBlob(''), textAsBlob('1'));"), + row(b"foo123", b"1", b"1", b"1"), + row(b"foo123", b"1", b"2", b"2")) + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND (c1, c2) >= (textAsBlob(''), textAsBlob('1'));"), + row(b"foo123", EMPTY_BYTE_BUFFER, b"1", b"4"), + row(b"foo123", b"1", b"1", b"1"), + row(b"foo123", b"1", b"2", b"2")) + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND (c1, c2) <= (textAsBlob(''), textAsBlob('1'));"), + row(b"foo123", EMPTY_BYTE_BUFFER, b"1", b"4")) + + assertEmpty(execute(cql, table, "SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND (c1, c2) < (textAsBlob(''), textAsBlob('1'));")) + +@pytest.mark.xfail(reason="issue #12749") +@pytest.mark.parametrize("options", [" WITH COMPACT STORAGE", " WITH COMPACT STORAGE AND CLUSTERING ORDER BY (c DESC)"]) +def testEmptyRestrictionValueWithOrderBy(cql, test_keyspace, options): + orderingClause = "" if "ORDER" in options else "ORDER BY c DESC" + with create_table(cql, test_keyspace, "(pk blob, c blob, v blob, PRIMARY KEY ((pk), c))" + options) as table: + execute(cql, table, "INSERT INTO %s (pk, c, v) VALUES (?, ?, ?)", + b"foo123", + b"1", + b"1") + execute(cql, table, "INSERT INTO %s (pk, c, v) VALUES (?, ?, ?)", + b"foo123", + b"2", + b"2") + + for _ in before_and_after_flush(cql, table): + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND c > textAsBlob('')" + orderingClause), + row(b"foo123", b"2", b"2"), + row(b"foo123", b"1", b"1")) + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND c >= textAsBlob('')" + orderingClause), + row(b"foo123", b"2", b"2"), + row(b"foo123", b"1", b"1")) + + assertEmpty(execute(cql, table, "SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND c < textAsBlob('')" + orderingClause)) + + assertEmpty(execute(cql, table, "SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND c <= textAsBlob('')" + orderingClause)) + + # Reproduces #12749: + assertInvalidMessage(cql, table, "Invalid empty or null value for column c", + "INSERT INTO %s (pk, c, v) VALUES (?, ?, ?)", + b"foo123", + EMPTY_BYTE_BUFFER, + b"4") + +@pytest.mark.xfail(reason="issue #12749") +@pytest.mark.parametrize("options", [" WITH COMPACT STORAGE", " WITH COMPACT STORAGE AND CLUSTERING ORDER BY (c1 DESC, c2 DESC)"]) +def testEmptyRestrictionValueWithMultipleClusteringColumnsAndOrderBy(cql, test_keyspace, options): + orderingClause = "" if "ORDER" in options else "ORDER BY c1 DESC, c2 DESC" + with create_table(cql, test_keyspace, "(pk blob, c1 blob, c2 blob, v blob, PRIMARY KEY (pk, c1, c2))" + options) as table: + execute(cql, table, "INSERT INTO %s (pk, c1, c2, v) VALUES (?, ?, ?, ?)", b"foo123", b"1", b"1", b"1") + execute(cql, table, "INSERT INTO %s (pk, c1, c2, v) VALUES (?, ?, ?, ?)", b"foo123", b"1", b"2", b"2") + for _ in before_and_after_flush(cql, table): + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND c1 > textAsBlob('')" + orderingClause), + row(b"foo123", b"1", b"2", b"2"), + row(b"foo123", b"1", b"1", b"1")) + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND c1 = textAsBlob('1') AND c2 > textAsBlob('')" + orderingClause), + row(b"foo123", b"1", b"2", b"2"), + row(b"foo123", b"1", b"1", b"1")) + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND (c1, c2) > (textAsBlob(''), textAsBlob('1'))" + orderingClause), + row(b"foo123", b"1", b"2", b"2"), + row(b"foo123", b"1", b"1", b"1")) + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND c1 = textAsBlob('1') AND c2 >= textAsBlob('')" + orderingClause), + row(b"foo123", b"1", b"2", b"2"), + row(b"foo123", b"1", b"1", b"1")) + execute(cql, table, "INSERT INTO %s (pk, c1, c2, v) VALUES (?, ?, ?, ?)", + b"foo123", EMPTY_BYTE_BUFFER, b"1", b"4") + + for _ in before_and_after_flush(cql, table): + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND c1 IN (textAsBlob(''), textAsBlob('1')) AND c2 = textAsBlob('1')" + orderingClause), + row(b"foo123", b"1", b"1", b"1"), + row(b"foo123", EMPTY_BYTE_BUFFER, b"1", b"4")) + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND (c1, c2) IN ((textAsBlob(''), textAsBlob('1')), (textAsBlob('1'), textAsBlob('1')))" + orderingClause), + row(b"foo123", b"1", b"1", b"1"), + row(b"foo123", EMPTY_BYTE_BUFFER, b"1", b"4")) + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND (c1, c2) > (textAsBlob(''), textAsBlob('1'))" + orderingClause), + row(b"foo123", b"1", b"2", b"2"), + row(b"foo123", b"1", b"1", b"1")) + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND (c1, c2) >= (textAsBlob(''), textAsBlob('1'))" + orderingClause), + row(b"foo123", b"1", b"2", b"2"), + row(b"foo123", b"1", b"1", b"1"), + row(b"foo123", EMPTY_BYTE_BUFFER, b"1", b"4")) +# UpdateTest +@pytest.mark.parametrize("forceFlush", [False, True]) +def testUpdate(cql, test_keyspace, forceFlush): + with create_table(cql, test_keyspace, "(partitionKey int, clustering_1 int, value int, PRIMARY KEY (partitionKey, clustering_1))" + compactOption) as table: + execute(cql, table, "INSERT INTO %s (partitionKey, clustering_1, value) VALUES (0, 0, 0)") + execute(cql, table, "INSERT INTO %s (partitionKey, clustering_1, value) VALUES (0, 1, 1)") + execute(cql, table, "INSERT INTO %s (partitionKey, clustering_1, value) VALUES (0, 2, 2)") + execute(cql, table, "INSERT INTO %s (partitionKey, clustering_1, value) VALUES (0, 3, 3)") + execute(cql, table, "INSERT INTO %s (partitionKey, clustering_1, value) VALUES (1, 0, 4)") + + if forceFlush: + nodetool.flush(cql, table) + + execute(cql, table, "UPDATE %s SET value = ? WHERE partitionKey = ? AND clustering_1 = ?", 7, 0, 1) + if forceFlush: + nodetool.flush(cql, table) + assert_rows(execute(cql, table, "SELECT value FROM %s WHERE partitionKey = ? AND clustering_1 = ?", + 0, 1), + row(7)) + + execute(cql, table, "UPDATE %s SET value = ? WHERE partitionKey = ? AND (clustering_1) = (?)", 8, 0, 2) + if forceFlush: + nodetool.flush(cql, table) + assert_rows(execute(cql, table, "SELECT value FROM %s WHERE partitionKey = ? AND clustering_1 = ?", + 0, 2), + row(8)) + + execute(cql, table, "UPDATE %s SET value = ? WHERE partitionKey IN (?, ?) AND clustering_1 = ?", 9, 0, 1, 0) + if forceFlush: + nodetool.flush(cql, table) + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE partitionKey IN (?, ?) AND clustering_1 = ?", + 0, 1, 0), + row(0, 0, 9), + row(1, 0, 9)) + + execute(cql, table, "UPDATE %s SET value = ? WHERE partitionKey IN ? AND clustering_1 = ?", 19, [0, 1], 0) + if forceFlush: + nodetool.flush(cql, table) + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE partitionKey IN ? AND clustering_1 = ?", + [0, 1], 0), + row(0, 0, 19), + row(1, 0, 19)) + + execute(cql, table, "UPDATE %s SET value = ? WHERE partitionKey = ? AND clustering_1 IN (?, ?)", 10, 0, 1, 0) + if forceFlush: + nodetool.flush(cql, table) + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE partitionKey = ? AND clustering_1 IN (?, ?)", + 0, 1, 0), + row(0, 0, 10), + row(0, 1, 10)) + + execute(cql, table, "UPDATE %s SET value = ? WHERE partitionKey = ? AND (clustering_1) IN ((?), (?))", 20, 0, 0, 1) + if forceFlush: + nodetool.flush(cql, table) + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE partitionKey = ? AND (clustering_1) IN ((?), (?))", + 0, 0, 1), + row(0, 0, 20), + row(0, 1, 20)) + + execute(cql, table, "UPDATE %s SET value = ? WHERE partitionKey = ? AND clustering_1 = ?", null, 0, 0) + if forceFlush: + nodetool.flush(cql, table) + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE partitionKey = ? AND (clustering_1) IN ((?), (?))", + 0, 0, 1), + row(0, 1, 20)) + # test invalid queries. Scylla and Cassandra error messages are + # different, so below we look for some common strings + + # missing primary key element + assertInvalidMessage(cql, table, "partitionkey", + "UPDATE %s SET value = ? WHERE clustering_1 = ? ", 7, 1) + + assertInvalidMessage(cql, table, "clustering_1", + "UPDATE %s SET value = ? WHERE partitionKey = ?", 7, 0) + + # token function + assertInvalidMessage(cql, table, "The token function cannot be used in WHERE clauses", + "UPDATE %s SET value = ? WHERE token(partitionKey) = token(?) AND clustering_1 = ?", + 7, 0, 1) + + # multiple time the same value + # Cassandra generates an InvalidSyntax here, Scylla InvalidRequest, + # both are reasonable. + assertInvalidThrow(cql, table, (SyntaxException, InvalidRequest), "UPDATE %s SET value = ?, value = ? WHERE partitionKey = ? AND clustering_1 = ?", 7, 0, 1) + + # multiple time same primary key element in WHERE clause + # This is allowed in Scylla so the test is commented out. + #assertInvalidMessage(cql, table, "clustering_1 cannot be restricted by more than one relation if it includes an Equal", + # "UPDATE %s SET value = ? WHERE partitionKey = ? AND clustering_1 = ? AND clustering_1 = ?", 7, 0, 1, 1) + + # Undefined column names + assertInvalidMessage(cql, table, "value1", + "UPDATE %s SET value1 = ? WHERE partitionKey = ? AND clustering_1 = ?", 7, 0, 1) + + assertInvalidMessage(cql, table, "partitionkey1", + "UPDATE %s SET value = ? WHERE partitionKey1 = ? AND clustering_1 = ?", 7, 0, 1) + + assertInvalidMessage(cql, table, "clustering_3", + "UPDATE %s SET value = ? WHERE partitionKey = ? AND clustering_3 = ?", 7, 0, 1) + + # Invalid operator in the where clause + assertInvalidMessage(cql, table, "Only EQ and IN relation are supported on the partition key", + "UPDATE %s SET value = ? WHERE partitionKey > ? AND clustering_1 = ?", 7, 0, 1) + + assertInvalidMessage(cql, table, "Cannot use CONTAINS on non-collection column", + "UPDATE %s SET value = ? WHERE partitionKey CONTAINS ? AND clustering_1 = ?", 7, 0, 1) + + assertInvalidMessage(cql, table, "value", + "UPDATE %s SET value = ? WHERE partitionKey = ? AND clustering_1 = ? AND value = ?", 7, 0, 1, 3) + + assertInvalid(cql, table, + "UPDATE %s SET value = ? WHERE partitionKey = ? AND clustering_1 > ?", 7, 0, 1) + +@pytest.mark.parametrize("forceFlush", [False, True]) +def testUpdateWithTwoClusteringColumns(cql, test_keyspace, forceFlush): + with create_table(cql, test_keyspace, "(partitionKey int, clustering_1 int, clustering_2 int, value int, PRIMARY KEY (partitionKey, clustering_1, clustering_2))" + compactOption) as table: + execute(cql, table, "INSERT INTO %s (partitionKey, clustering_1, clustering_2, value) VALUES (0, 0, 0, 0)") + execute(cql, table, "INSERT INTO %s (partitionKey, clustering_1, clustering_2, value) VALUES (0, 0, 1, 1)") + execute(cql, table, "INSERT INTO %s (partitionKey, clustering_1, clustering_2, value) VALUES (0, 0, 2, 2)") + execute(cql, table, "INSERT INTO %s (partitionKey, clustering_1, clustering_2, value) VALUES (0, 0, 3, 3)") + execute(cql, table, "INSERT INTO %s (partitionKey, clustering_1, clustering_2, value) VALUES (0, 1, 1, 4)") + execute(cql, table, "INSERT INTO %s (partitionKey, clustering_1, clustering_2, value) VALUES (0, 1, 2, 5)") + execute(cql, table, "INSERT INTO %s (partitionKey, clustering_1, clustering_2, value) VALUES (1, 0, 0, 6)") + if forceFlush: + nodetool.flush(cql, table) + + execute(cql, table, "UPDATE %s SET value = ? WHERE partitionKey = ? AND clustering_1 = ? AND clustering_2 = ?", 7, 0, 1, 1) + if forceFlush: + nodetool.flush(cql, table) + assert_rows(execute(cql, table, "SELECT value FROM %s WHERE partitionKey = ? AND clustering_1 = ? AND clustering_2 = ?", + 0, 1, 1), + row(7)) + + execute(cql, table, "UPDATE %s SET value = ? WHERE partitionKey = ? AND (clustering_1, clustering_2) = (?, ?)", 8, 0, 1, 2) + if forceFlush: + nodetool.flush(cql, table) + assert_rows(execute(cql, table, "SELECT value FROM %s WHERE partitionKey = ? AND clustering_1 = ? AND clustering_2 = ?", + 0, 1, 2), + row(8)) + + execute(cql, table, "UPDATE %s SET value = ? WHERE partitionKey IN (?, ?) AND clustering_1 = ? AND clustering_2 = ?", 9, 0, 1, 0, 0) + if forceFlush: + nodetool.flush(cql, table) + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE partitionKey IN (?, ?) AND clustering_1 = ? AND clustering_2 = ?", + 0, 1, 0, 0), + row(0, 0, 0, 9), + row(1, 0, 0, 9)) + + execute(cql, table, "UPDATE %s SET value = ? WHERE partitionKey IN ? AND clustering_1 = ? AND clustering_2 = ?", 9, [0, 1], 0, 0) + if forceFlush: + nodetool.flush(cql, table) + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE partitionKey IN ? AND clustering_1 = ? AND clustering_2 = ?", + [0, 1], 0, 0), + row(0, 0, 0, 9), + row(1, 0, 0, 9)) + + execute(cql, table, "UPDATE %s SET value = ? WHERE partitionKey = ? AND clustering_1 = ? AND clustering_2 IN (?, ?)", 12, 0, 1, 1, 2) + if forceFlush: + nodetool.flush(cql, table) + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE partitionKey = ? AND clustering_1 = ? AND clustering_2 IN (?, ?)", + 0, 1, 1, 2), + row(0, 1, 1, 12), + row(0, 1, 2, 12)) + + execute(cql, table, "UPDATE %s SET value = ? WHERE partitionKey = ? AND clustering_1 IN (?, ?) AND clustering_2 IN (?, ?)", 10, 0, 1, 0, 1, 2) + if forceFlush: + nodetool.flush(cql, table) + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE partitionKey = ? AND clustering_1 IN (?, ?) AND clustering_2 IN (?, ?)", + 0, 1, 0, 1, 2), + row(0, 0, 1, 10), + row(0, 0, 2, 10), + row(0, 1, 1, 10), + row(0, 1, 2, 10)) + + execute(cql, table, "UPDATE %s SET value = ? WHERE partitionKey = ? AND (clustering_1, clustering_2) IN ((?, ?), (?, ?))", 20, 0, 0, 2, 1, 2) + if forceFlush: + nodetool.flush(cql, table) + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE partitionKey = ? AND (clustering_1, clustering_2) IN ((?, ?), (?, ?))", + 0, 0, 2, 1, 2), + row(0, 0, 2, 20), + row(0, 1, 2, 20)) + + execute(cql, table, "UPDATE %s SET value = ? WHERE partitionKey = ? AND clustering_1 = ? AND clustering_2 = ?", null, 0, 0, 2) + if forceFlush: + nodetool.flush(cql, table) + + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE partitionKey = ? AND (clustering_1, clustering_2) IN ((?, ?), (?, ?))", + 0, 0, 2, 1, 2), + row(0, 1, 2, 20)) + + # test invalid queries. Scylla and Cassandra error messages are + # different, so below we look for some common strings + + # missing primary key element + assertInvalidMessage(cql, table, "partitionkey", + "UPDATE %s SET value = ? WHERE clustering_1 = ? AND clustering_2 = ?", 7, 1, 1) + + errorMsg = 'PRIMARY KEY column "clustering_2" cannot be restricted as preceding column "clustering_1" is not restricted' + + assertInvalidMessage(cql, table, errorMsg, + "UPDATE %s SET value = ? WHERE partitionKey = ? AND clustering_2 = ?", 7, 0, 1) + + assertInvalidMessage(cql, table, "clustering_1", + "UPDATE %s SET value = ? WHERE partitionKey = ?", 7, 0) + + # token function + assertInvalidMessage(cql, table, "The token function cannot be used in WHERE clauses", + "UPDATE %s SET value = ? WHERE token(partitionKey) = token(?) AND clustering_1 = ? AND clustering_2 = ?", + 7, 0, 1, 1) + + # multiple time the same value + # Cassandra generates an InvalidSyntax here, Scylla InvalidRequest, + # both are reasonable. + assertInvalidThrow(cql, table, (SyntaxException, InvalidRequest), "UPDATE %s SET value = ?, value = ? WHERE partitionKey = ? AND clustering_1 = ? AND clustering_2 = ?", 7, 0, 1, 1) + + # multiple time same primary key element in WHERE clause + # Scylla allows this, so test commented out. + #assertInvalidMessage(cql, table, "clustering_1 cannot be restricted by more than one relation if it includes an Equal", + # "UPDATE %s SET value = ? WHERE partitionKey = ? AND clustering_1 = ? AND clustering_2 = ? AND clustering_1 = ?", 7, 0, 1, 1, 1) + + # Undefined column names + assertInvalidMessage(cql, table, "value1", + "UPDATE %s SET value1 = ? WHERE partitionKey = ? AND clustering_1 = ? AND clustering_2 = ?", 7, 0, 1, 1) + + assertInvalidMessage(cql, table, "partitionkey1", + "UPDATE %s SET value = ? WHERE partitionKey1 = ? AND clustering_1 = ? AND clustering_2 = ?", 7, 0, 1, 1) + + assertInvalidMessage(cql, table, "clustering_3", + "UPDATE %s SET value = ? WHERE partitionKey = ? AND clustering_1 = ? AND clustering_3 = ?", 7, 0, 1, 1) + + # Invalid operator in the where clause + assertInvalidMessage(cql, table, "Only EQ and IN relation are supported on the partition key", + "UPDATE %s SET value = ? WHERE partitionKey > ? AND clustering_1 = ? AND clustering_2 = ?", 7, 0, 1, 1) + + assertInvalidMessage(cql, table, "Cannot use CONTAINS on non-collection column", + "UPDATE %s SET value = ? WHERE partitionKey CONTAINS ? AND clustering_1 = ? AND clustering_2 = ?", 7, 0, 1, 1) + + assertInvalid(cql, table, + "UPDATE %s SET value = ? WHERE partitionKey = ? AND clustering_1 = ? AND clustering_2 = ? AND value = ?", 7, 0, 1, 1, 3) + + assertInvalid(cql, table, + "UPDATE %s SET value = ? WHERE partitionKey = ? AND clustering_1 > ?", 7, 0, 1) + + assertInvalid(cql, table, + "UPDATE %s SET value = ? WHERE partitionKey = ? AND (clustering_1, clustering_2) > (?, ?)", 7, 0, 1, 1) + +@pytest.mark.parametrize("forceFlush", [False, True]) +def testUpdateWithMultiplePartitionKeyComponents(cql, test_keyspace, forceFlush): + with create_table(cql, test_keyspace, "(partitionKey_1 int, partitionKey_2 int, clustering_1 int, clustering_2 int, value int, PRIMARY KEY ((partitionKey_1, partitionKey_2), clustering_1, clustering_2))" + compactOption) as table: + execute(cql, table, "INSERT INTO %s (partitionKey_1, partitionKey_2, clustering_1, clustering_2, value) VALUES (0, 0, 0, 0, 0)") + execute(cql, table, "INSERT INTO %s (partitionKey_1, partitionKey_2, clustering_1, clustering_2, value) VALUES (0, 1, 0, 1, 1)") + execute(cql, table, "INSERT INTO %s (partitionKey_1, partitionKey_2, clustering_1, clustering_2, value) VALUES (0, 1, 1, 1, 2)") + execute(cql, table, "INSERT INTO %s (partitionKey_1, partitionKey_2, clustering_1, clustering_2, value) VALUES (1, 0, 0, 1, 3)") + execute(cql, table, "INSERT INTO %s (partitionKey_1, partitionKey_2, clustering_1, clustering_2, value) VALUES (1, 1, 0, 1, 3)") + if forceFlush: + nodetool.flush(cql, table) + + execute(cql, table, "UPDATE %s SET value = ? WHERE partitionKey_1 = ? AND partitionKey_2 = ? AND clustering_1 = ? AND clustering_2 = ?", 7, 0, 0, 0, 0) + if forceFlush: + nodetool.flush(cql, table) + assert_rows(execute(cql, table, "SELECT value FROM %s WHERE partitionKey_1 = ? AND partitionKey_2 = ? AND clustering_1 = ? AND clustering_2 = ?", + 0, 0, 0, 0), + row(7)) + + execute(cql, table, "UPDATE %s SET value = ? WHERE partitionKey_1 IN (?, ?) AND partitionKey_2 = ? AND clustering_1 = ? AND clustering_2 = ?", 9, 0, 1, 1, 0, 1) + if forceFlush: + nodetool.flush(cql, table) + assert_rows(execute(cql, table, "SELECT * FROM %s WHERE partitionKey_1 IN (?, ?) AND partitionKey_2 = ? AND clustering_1 = ? AND clustering_2 = ?", + 0, 1, 1, 0, 1), + row(0, 1, 0, 1, 9), + row(1, 1, 0, 1, 9)) + + execute(cql, table, "UPDATE %s SET value = ? WHERE partitionKey_1 IN (?, ?) AND partitionKey_2 IN (?, ?) AND clustering_1 = ? AND clustering_2 = ?", 10, 0, 1, 0, 1, 0, 1) + if forceFlush: + nodetool.flush(cql, table) + assert_rows(execute(cql, table, "SELECT * FROM %s"), + row(0, 0, 0, 0, 7), + row(0, 0, 0, 1, 10), + row(0, 1, 0, 1, 10), + row(0, 1, 1, 1, 2), + row(1, 0, 0, 1, 10), + row(1, 1, 0, 1, 10)) + + # missing primary key element + # There are two ways to fix the following broken request. Cassandra + # mentions one fix in the error message - that a partition key + # component is missing - and Scylla mentions a different fix in the + # error message - that ALLOW FILTERING can be used. Let's just agree + # there should be an error. + assertInvalid(cql, table, + "UPDATE %s SET value = ? WHERE partitionKey_1 = ? AND clustering_1 = ? AND clustering_2 = ?", 7, 1, 1) + +# AlterTest + +# Test for CASSANDRA-13917 +def testAlterWithCompactStaticFormat(cql, test_keyspace): + with create_table(cql, test_keyspace, "(a int PRIMARY KEY, b int, c int) WITH COMPACT STORAGE") as table: + assertInvalidMessage(cql, table, "column1", + "ALTER TABLE %s RENAME column1 TO column2") + +# Test for CASSANDRA-13917 +def testAlterWithCompactNonStaticFormat(cql, test_keyspace): + with create_table(cql, test_keyspace, "(a int, b int, PRIMARY KEY (a,b)) WITH COMPACT STORAGE") as table: + assertInvalidMessage(cql, table, "column1", + "ALTER TABLE %s RENAME column1 TO column2") + + with create_table(cql, test_keyspace, "(a int, b int, v int, PRIMARY KEY (a,b)) WITH COMPACT STORAGE") as table: + assertInvalidMessage(cql, table, "column1", + "ALTER TABLE %s RENAME column1 TO column2") + +# CreateTest + +# Test for CASSANDRA-13917 +def testCreateIndextWithCompactStaticFormat(cql, test_keyspace): + with create_table(cql, test_keyspace, "(a int PRIMARY KEY, b int, c int) WITH COMPACT STORAGE") as table: + assertInvalidMessage(cql, table, "column1", + "CREATE INDEX column1_index on %s (column1)") + assertInvalidMessage(cql, table, "value", + "CREATE INDEX value_index on %s (value)") + +# DeleteTest + +# Test for CASSANDRA-13917 +def testDeleteWithCompactStaticFormat(cql, test_keyspace): + with create_table(cql, test_keyspace, "(a int PRIMARY KEY, b int, c int) WITH COMPACT STORAGE") as table: + do_testDeleteWithCompactFormat(cql, table) + + # if column1 is present, hidden column is called column2 + with create_table(cql, test_keyspace, "(a int PRIMARY KEY, b int, c int, column1 int) WITH COMPACT STORAGE") as table: + assertInvalidMessage(cql, table, "column2", + "DELETE FROM %s WHERE a = 1 AND column2= 1") + assertInvalidMessage(cql, table, "column2", + "DELETE FROM %s WHERE a = 1 AND column2 = 1 AND value1 = 1") + assertInvalidMessage(cql, table, "column2", + "DELETE column2 FROM %s WHERE a = 1") + + # if value is present, hidden column is called value1 + with create_table(cql, test_keyspace, "(a int PRIMARY KEY, b int, c int, value int) WITH COMPACT STORAGE") as table: + assertInvalidMessage(cql, table, "value1", + "DELETE FROM %s WHERE a = 1 AND value1 = 1") + assertInvalidMessage(cql, table, "value1", + "DELETE FROM %s WHERE a = 1 AND value1 = 1 AND column1 = 1") + assertInvalidMessage(cql, table, "value1", + "DELETE value1 FROM %s WHERE a = 1") + +# Test for CASSANDRA-13917 +# Reproduces #12815 +@pytest.mark.xfail(reason="issue #12815") +def testDeleteWithCompactNonStaticFormat(cql, test_keyspace): + with create_table(cql, test_keyspace, "(a int, b int, PRIMARY KEY (a, b)) WITH COMPACT STORAGE") as table: + execute(cql, table, "INSERT INTO %s (a, b) VALUES (1, 1)") + execute(cql, table, "INSERT INTO %s (a, b) VALUES (2, 1)") + assert_rows(execute(cql, table, "SELECT a, b FROM %s"), + row(1, 1), + row(2, 1)) + do_testDeleteWithCompactFormat(cql, table) + + with create_table(cql, test_keyspace, "(a int, b int, v int, PRIMARY KEY (a, b)) WITH COMPACT STORAGE") as table: + execute(cql, table, "INSERT INTO %s (a, b, v) VALUES (1, 1, 3)") + execute(cql, table, "INSERT INTO %s (a, b, v) VALUES (2, 1, 4)") + assert_rows(execute(cql, table, "SELECT a, b, v FROM %s"), + row(1, 1, 3), + row(2, 1, 4)) + do_testDeleteWithCompactFormat(cql, table) + +def do_testDeleteWithCompactFormat(cql, table): + assertInvalidMessage(cql, table, "value", + "DELETE FROM %s WHERE a = 1 AND value = 1") + assertInvalidMessage(cql, table, "column1", + "DELETE FROM %s WHERE a = 1 AND column1= 1") + assertInvalidMessage(cql, table, "value", + "DELETE FROM %s WHERE a = 1 AND value = 1 AND column1 = 1") + assertInvalidMessage(cql, table, "value", + "DELETE value FROM %s WHERE a = 1") + assertInvalidMessage(cql, table, "column1", + "DELETE column1 FROM %s WHERE a = 1") + +# InsertTest + +# Test for CASSANDRA-13917 +def testInsertWithCompactStaticFormat(cql, test_keyspace): + do_testInsertWithCompactTable(cql, test_keyspace, "(a int PRIMARY KEY, b int, c int) WITH COMPACT STORAGE") + # if column1 is present, hidden column is called column2 + with create_table(cql, test_keyspace, "(a int PRIMARY KEY, b int, c int, column1 int) WITH COMPACT STORAGE") as table: + execute(cql, table, "INSERT INTO %s (a, b, c, column1) VALUES (1, 1, 1, 1)") + assertInvalidMessage(cql, table, "column2", + "INSERT INTO %s (a, b, c, column2) VALUES (1, 1, 1, 1)") + + # if value is present, hidden column is called value1 + with create_table(cql, test_keyspace, "(a int PRIMARY KEY, b int, c int, value int) WITH COMPACT STORAGE") as table: + execute(cql, table, "INSERT INTO %s (a, b, c, value) VALUES (1, 1, 1, 1)") + assertInvalidMessage(cql, table, "value1", + "INSERT INTO %s (a, b, c, value1) VALUES (1, 1, 1, 1)") + +# Test for CASSANDRA-13917 +# Reproduces #12815. +# Because it currently crashes Scylla we have to skip it instead of xfail... +@pytest.mark.skip(reason="issue #12815") +def testInsertWithCompactNonStaticFormat(cql, test_keyspace): + do_testInsertWithCompactTable(cql, test_keyspace, "(a int, b int, PRIMARY KEY (a, b)) WITH COMPACT STORAGE") + do_testInsertWithCompactTable(cql, test_keyspace, "(a int, b int, v int, PRIMARY KEY (a, b)) WITH COMPACT STORAGE") + +def do_testInsertWithCompactTable(cql, test_keyspace, create): + with create_table(cql, test_keyspace, create) as table: + + # pass correct types to the hidden columns + assertInvalidMessage(cql, table, "column1", + "INSERT INTO %s (a, b, column1) VALUES (?, ?, ?)", + 1, 1, 1, b'a') + assertInvalidMessage(cql, table, "value", + "INSERT INTO %s (a, b, value) VALUES (?, ?, ?)", + 1, 1, 1, b'a') + assertInvalidMessage(cql, table, "column1", + "INSERT INTO %s (a, b, column1, value) VALUES (?, ?, ?, ?)", + 1, 1, 1, b'a', b'b') + assertInvalidMessage(cql, table, "value", + "INSERT INTO %s (a, b, value, column1) VALUES (?, ?, ?, ?)", + 1, 1, 1, b'a', b'b') + + # pass incorrect types to the hidden columns + assertInvalidMessage(cql, table, "value", + "INSERT INTO %s (a, b, value) VALUES (?, ?, ?)", + 1, 1, 1, 1) + assertInvalidMessage(cql, table, "column1", + "INSERT INTO %s (a, b, column1) VALUES (?, ?, ?)", + 1, 1, 1, 1) + assertEmpty(execute(cql, table, "SELECT * FROM %s")) + + # pass null to the hidden columns + assertInvalidMessage(cql, table, "value", + "INSERT INTO %s (a, b, value) VALUES (?, ?, ?)", + 1, 1, None) + assertInvalidMessage(cql, table, "column1", + "INSERT INTO %s (a, b, column1) VALUES (?, ?, ?)", + 1, 1, None) + +# SelectTest + +# Test for CASSANDRA-13917 +def testSelectWithCompactStaticFormat(cql, test_keyspace): + with create_table(cql, test_keyspace, "(a int PRIMARY KEY, b int, c int) WITH COMPACT STORAGE") as table: + execute(cql, table, "INSERT INTO %s (a, b, c) VALUES (1, 1, 1)") + execute(cql, table, "INSERT INTO %s (a, b, c) VALUES (2, 1, 1)") + assert_rows(execute(cql, table, "SELECT a, b, c FROM %s"), + row(1, 1, 1), + row(2, 1, 1)) + do_testSelectWithCompactFormat(cql, table) + + # if column column1 is present, hidden column is called column2 + with create_table(cql, test_keyspace, "(a int PRIMARY KEY, b int, c int, column1 int) WITH COMPACT STORAGE") as table: + execute(cql, table, "INSERT INTO %s (a, b, c, column1) VALUES (1, 1, 1, 1)") + execute(cql, table, "INSERT INTO %s (a, b, c, column1) VALUES (2, 1, 1, 2)") + assert_rows(execute(cql, table, "SELECT a, b, c, column1 FROM %s"), + row(1, 1, 1, 1), + row(2, 1, 1, 2)) + assertInvalidMessage(cql, table, "column2", + "SELECT a, column2, value FROM %s") + + # if column value is present, hidden column is called value1 + with create_table(cql, test_keyspace, "(a int PRIMARY KEY, b int, c int, value int) WITH COMPACT STORAGE") as table: + execute(cql, table, "INSERT INTO %s (a, b, c, value) VALUES (1, 1, 1, 1)") + execute(cql, table, "INSERT INTO %s (a, b, c, value) VALUES (2, 1, 1, 2)") + assert_rows(execute(cql, table, "SELECT a, b, c, value FROM %s"), + row(1, 1, 1, 1), + row(2, 1, 1, 2)) + assertInvalidMessage(cql, table, "value1", + "SELECT a, value1, value FROM %s") + +# Test for CASSANDRA-13917 +# Reproduces #12815. +# Because it currently crashes Scylla we have to skip it instead of xfail... +@pytest.mark.skip(reason="issue #12815") +def testSelectWithCompactNonStaticFormat(cql, test_keyspace): + with create_table(cql, test_keyspace, "(a int, b int, PRIMARY KEY (a,b)) WITH COMPACT STORAGE") as table: + execute(cql, table, "INSERT INTO %s (a, b) VALUES (1, 1)") + execute(cql, table, "INSERT INTO %s (a, b) VALUES (2, 1)") + assert_rows(execute(cql, table, "SELECT a, b FROM %s"), + row(1, 1), + row(2, 1)) + do_testSelectWithCompactFormat(cql, table) + + with create_table(cql, test_keyspace, "(a int, b int, v int, PRIMARY KEY (a,b)) WITH COMPACT STORAGE") as table: + execute(cql, table, "INSERT INTO %s (a, b, v) VALUES (1, 1, 3)") + execute(cql, table, "INSERT INTO %s (a, b, v) VALUES (2, 1, 4)") + assert_rows(execute(cql, table, "SELECT a, b, v FROM %s"), + row(1, 1, 3), + row(2, 1, 4)) + do_testSelectWithCompactFormat(cql, table) + +def do_testSelectWithCompactFormat(cql, table): + assertInvalidMessage(cql, table, "column1", + "SELECT column1 FROM %s") + assertInvalidMessage(cql, table, "value", + "SELECT value FROM %s") + assertInvalidMessage(cql, table, "value", + "SELECT value, column1 FROM %s") + assertInvalidMessage(cql, table, "column1", + "SELECT * FROM %s WHERE column1 = null ALLOW FILTERING") + assertInvalidMessage(cql, table, "value", + "SELECT * FROM %s WHERE value = null ALLOW FILTERING") + assertInvalidMessage(cql, table, "column1", + "SELECT WRITETIME(column1) FROM %s") + assertInvalidMessage(cql, table, "value", + "SELECT WRITETIME(value) FROM %s") + +# UpdateTest + +# Test for CASSANDRA-13917 +def testUpdateWithCompactStaticFormat(cql, test_keyspace): + do_testUpdateWithCompactFormat(cql, test_keyspace, "(a int PRIMARY KEY, b int, c int) WITH COMPACT STORAGE") + with create_table(cql, test_keyspace, "(a int PRIMARY KEY, b int, c int) WITH COMPACT STORAGE") as table: + assertInvalidMessage(cql, table, "column1", + "UPDATE %s SET b = 1 WHERE column1 = ?", + b'a') + assertInvalidMessage(cql, table, "value", + "UPDATE %s SET b = 1 WHERE value = ?", + b'a') + + # if column1 is present, hidden column is called column2 + with create_table(cql, test_keyspace, "(a int PRIMARY KEY, b int, c int, column1 int) WITH COMPACT STORAGE") as table: + execute(cql, table, "INSERT INTO %s (a, b, c, column1) VALUES (1, 1, 1, 1)") + execute(cql, table, "UPDATE %s SET column1 = 6 WHERE a = 1") + assertInvalidMessage(cql, table, "column2", "UPDATE %s SET column2 = 6 WHERE a = 0") + assertInvalidMessage(cql, table, "value", "UPDATE %s SET value = 6 WHERE a = 0") + + # if value is present, hidden column is called value1 + with create_table(cql, test_keyspace, "(a int PRIMARY KEY, b int, c int, value int) WITH COMPACT STORAGE") as table: + execute(cql, table, "INSERT INTO %s (a, b, c, value) VALUES (1, 1, 1, 1)") + execute(cql, table, "UPDATE %s SET value = 6 WHERE a = 1") + assertInvalidMessage(cql, table, "column1", "UPDATE %s SET column1 = 6 WHERE a = 1") + assertInvalidMessage(cql, table, "value1", "UPDATE %s SET value1 = 6 WHERE a = 1") + +# Test for CASSANDRA-13917 +# Reproduces #12815. +# Because it currently crashes Scylla we have to skip it instead of xfail... +@pytest.mark.skip(reason="issue #12815") +def testUpdateWithCompactNonStaticFormat(cql, test_keyspace): + do_testUpdateWithCompactFormat(cql, test_keyspace, "(a int, b int, PRIMARY KEY (a, b)) WITH COMPACT STORAGE") + do_testUpdateWithCompactFormat(cql, test_keyspace, "(a int, b int, v int, PRIMARY KEY (a, b)) WITH COMPACT STORAGE") + +def do_testUpdateWithCompactFormat(cql, test_keyspace, create): + with create_table(cql, test_keyspace, create) as table: + # pass correct types to hidden columns + assertInvalidMessage(cql, table, "column1", + "UPDATE %s SET column1 = ? WHERE a = 0", + b'a') + assertInvalidMessage(cql, table, "value", + "UPDATE %s SET value = ? WHERE a = 0", + b'a') + + # pass incorrect types to hidden columns + assertInvalidMessage(cql, table, "column1", "UPDATE %s SET column1 = 6 WHERE a = 0") + assertInvalidMessage(cql, table, "value", "UPDATE %s SET value = 6 WHERE a = 0")