mirror of
https://github.com/scylladb/scylladb.git
synced 2026-05-12 19:02:12 +00:00
Merge 'cql3: don't ignore other restrictions when a multi column restriction is present during filtering' from Jan Ciołek
When filtering with multi column restriction present all other restrictions were ignored. So a query like: `SELECT * FROM WHERE pk = 0 AND (ck1, ck2) < (0, 0) AND regular_col = 0 ALLOW FILTERING;` would ignore the restriction `regular_col = 0`. This was caused by a bug in the filtering code:2779a171fc/cql3/selection/selection.cc (L433-L449)When multi column restrictions were detected, the code checked if they are satisfied and returned immediately. This is fixed by returning only when these restrictions are not satisfied. When they are satisfied the other restrictions are checked as well to ensure all of them are satisfied. This code was introduced back in 2019, when fixing #3574. Perhaps back then it was impossible to mix multi column and regular columns and this approach was correct. Fixes: #6200 Fixes: #12014 Closes #12031 * github.com:scylladb/scylladb: cql-pytest: add a reproducer for #12014, verify that filtering multi column and regular restrictions works boost/restrictions-test: uncomment part of the test that passes now cql-pytest: enable test for filtering combined multi column and regular column restrictions cql3: don't ignore other restrictions when a multi column restriction is present during filtering (cherry picked from commit2d2034ea28) Closes #12086
This commit is contained in:
@@ -450,11 +450,16 @@ bool result_set_builder::restrictions_filter::do_filter(const selection& selecti
|
||||
}
|
||||
|
||||
auto clustering_columns_restrictions = _restrictions->get_clustering_columns_restrictions();
|
||||
if (dynamic_pointer_cast<cql3::restrictions::multi_column_restriction>(clustering_columns_restrictions)) {
|
||||
bool has_multi_col_clustering_restrictions =
|
||||
dynamic_pointer_cast<cql3::restrictions::multi_column_restriction>(clustering_columns_restrictions) != nullptr;
|
||||
if (has_multi_col_clustering_restrictions) {
|
||||
clustering_key_prefix ckey = clustering_key_prefix::from_exploded(clustering_key);
|
||||
return expr::is_satisfied_by(
|
||||
bool multi_col_clustering_satisfied = expr::is_satisfied_by(
|
||||
clustering_columns_restrictions->expression,
|
||||
partition_key, clustering_key, static_row, row, selection, _options);
|
||||
if (!multi_col_clustering_satisfied) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
auto static_row_iterator = static_row.iterator();
|
||||
@@ -502,6 +507,13 @@ bool result_set_builder::restrictions_filter::do_filter(const selection& selecti
|
||||
if (_skip_ck_restrictions) {
|
||||
continue;
|
||||
}
|
||||
if (has_multi_col_clustering_restrictions) {
|
||||
// Mixing multi column and single column restrictions on clustering
|
||||
// key columns is forbidden.
|
||||
// Since there are multi column restrictions we have to skip
|
||||
// evaluating single column restrictions or we will get an error.
|
||||
continue;
|
||||
}
|
||||
auto clustering_key_restrictions_map = _restrictions->get_single_column_clustering_key_restrictions();
|
||||
auto restr_it = clustering_key_restrictions_map.find(cdef);
|
||||
if (restr_it == clustering_key_restrictions_map.end()) {
|
||||
|
||||
@@ -763,9 +763,8 @@ SEASTAR_THREAD_TEST_CASE(multi_col_in) {
|
||||
cquery_nofail(e, "insert into t(pk,ck1,ck2,r) values (4,13,23,'a')");
|
||||
require_rows(e, "select pk from t where (ck1,ck2) in ((13,23)) allow filtering", {{I(3)}, {I(4)}});
|
||||
require_rows(e, "select pk from t where (ck1) in ((13),(33),(44)) allow filtering", {{I(3)}, {I(4)}});
|
||||
// TODO: uncomment when #6200 is fixed.
|
||||
// require_rows(e, "select pk from t where (ck1,ck2) in ((13,23)) and r='a' allow filtering",
|
||||
// {{I(4), I(13), F(23), T("a")}});
|
||||
require_rows(e, "select pk from t where (ck1,ck2) in ((13,23)) and r='a' allow filtering",
|
||||
{{I(4), I(13), F(23), T("a")}});
|
||||
cquery_nofail(e, "delete from t where pk=4");
|
||||
require_rows(e, "select pk from t where (ck1,ck2) in ((13,23)) allow filtering", {{I(3)}});
|
||||
auto stmt = e.prepare("select ck1 from t where (ck1,ck2) in ? allow filtering").get0();
|
||||
|
||||
@@ -27,3 +27,38 @@ def test_scan_ending_with_static_row(cql, test_keyspace):
|
||||
# results. The success criteria for this test is the query finishing
|
||||
# without errors.
|
||||
res = list(cql.execute(statement))
|
||||
|
||||
|
||||
# Test that if we have multi-column restrictions on the clustering key
|
||||
# and additional filtering on regular columns, both restrictions are obeyed.
|
||||
# Reproduces #6200.
|
||||
def test_multi_column_restrictions_and_filtering(cql, test_keyspace):
|
||||
with new_test_table(cql, test_keyspace, "p int, c1 int, c2 int, r int, PRIMARY KEY (p, c1, c2)") as table:
|
||||
stmt = cql.prepare(f"INSERT INTO {table} (p, c1, c2, r) VALUES (1, ?, ?, ?)")
|
||||
for i in range(2):
|
||||
for j in range(2):
|
||||
cql.execute(stmt, [i, j, j])
|
||||
assert list(cql.execute(f"SELECT c1,c2,r FROM {table} WHERE p=1 AND (c1, c2) = (0,1)")) == [(0,1,1)]
|
||||
# Since in that result r=1, adding "AND r=1" should return the same
|
||||
# result, and adding "AND r=0" should return nothing.
|
||||
assert list(cql.execute(f"SELECT c1,c2,r FROM {table} WHERE p=1 AND (c1, c2) = (0,1) AND r=1 ALLOW FILTERING")) == [(0,1,1)]
|
||||
# Reproduces #6200:
|
||||
assert list(cql.execute(f"SELECT c1,c2,r FROM {table} WHERE p=1 AND (c1, c2) = (0,1) AND r=0 ALLOW FILTERING")) == []
|
||||
|
||||
# Test that if we have a range multi-column restrictions on the clustering key
|
||||
# and additional filtering on regular columns, both restrictions are obeyed.
|
||||
# Similar to test_multi_column_restrictions_and_filtering, but uses a range
|
||||
# restriction on the clustering key columns.
|
||||
# Reproduces #12014, the code is taken from a reproducer provided by a user.
|
||||
def test_multi_column_range_restrictions_and_filtering(cql, test_keyspace):
|
||||
with new_test_table(cql, test_keyspace, "pk int, ts timestamp, id int, processed boolean, PRIMARY KEY (pk, ts, id)") as table:
|
||||
cql.execute(f"INSERT INTO {table} (pk, ts, id, processed) VALUES (0, currentTimestamp(), 0, true)")
|
||||
cql.execute(f"INSERT INTO {table} (pk, ts, id, processed) VALUES (0, currentTimestamp(), 1, true)")
|
||||
cql.execute(f"INSERT INTO {table} (pk, ts, id, processed) VALUES (0, currentTimestamp(), 2, false)")
|
||||
cql.execute(f"INSERT INTO {table} (pk, ts, id, processed) VALUES (0, currentTimestamp(), 3, false)")
|
||||
# This select doesn't use multi-column restrictions, the result shouldn't change when it does.
|
||||
rows1 = list(cql.execute(f"SELECT id, processed FROM {table} WHERE pk = 0 AND ts >= 0 AND processed = false ALLOW FILTERING"))
|
||||
assert rows1 == [(2, False), (3, False)]
|
||||
# Reproduces #12014
|
||||
rows2 = list(cql.execute(f"SELECT id, processed FROM {table} WHERE pk = 0 AND (ts, id) >= (0, 0) AND processed = false ALLOW FILTERING"))
|
||||
assert rows1 == rows2
|
||||
|
||||
Reference in New Issue
Block a user