Files
scylladb/test/boost/restrictions_test.cc
Pavel Emelyanov 54edb44b20 code: Stop using seastar::compat::source_location
And switch to std::source_location.
Upcoming seastar update will deprecate its compatibility layer.

The patch is

  for f in $(git grep -l 'seastar::compat::source_location'); do
    sed -e 's/seastar::compat::source_location/std::source_location/g' -i $f;
  done

and removal of few header includes.

Signed-off-by: Pavel Emelyanov <xemul@scylladb.com>

Closes scylladb/scylladb#27309
2025-11-27 19:10:11 +02:00

1055 lines
67 KiB
C++

/*
* Copyright (C) 2020-present ScyllaDB
*/
/*
* SPDX-License-Identifier: LicenseRef-ScyllaDB-Source-Available-1.0
*/
#include <fmt/format.h>
#include <fmt/ranges.h>
#undef SEASTAR_TESTING_MAIN
#include <seastar/testing/test_case.hh>
#include <seastar/testing/thread_test_case.hh>
#include "cql3/cql_config.hh"
#include "cql3/values.hh"
#include "cql3/query_options.hh"
#include "db/config.hh"
#include "test/lib/cql_assertions.hh"
#include "test/lib/cql_test_env.hh"
#include "test/lib/exception_utils.hh"
#include "types/list.hh"
#include "types/map.hh"
#include "types/set.hh"
BOOST_AUTO_TEST_SUITE(restrictions_test)
namespace {
using std::source_location;
std::unique_ptr<cql3::query_options> to_options(
const cql3::cql_config& cfg,
std::optional<std::vector<std::string_view>> names,
std::vector<cql3::raw_value> values) {
static auto& d = cql3::query_options::DEFAULT;
return std::make_unique<cql3::query_options>(
cfg,
d.get_consistency(), std::move(names), std::move(values), d.skip_metadata(),
d.get_specific_options());
}
/// Asserts that e.execute_prepared(id, values) contains expected rows, in any order.
void require_rows(cql_test_env& e,
cql3::prepared_cache_key_type id,
std::optional<std::vector<std::string_view>> names,
const std::vector<bytes_opt>& values,
const std::vector<std::vector<bytes_opt>>& expected,
const std::source_location& loc = source_location::current()) {
// This helps compiler pick the right overload for make_value:
const auto rvals = values | std::views::transform([] (const bytes_opt& v) { return cql3::raw_value::make_value(v); });
cql3::cql_config cfg(cql3::cql_config::default_tag{});
auto opts = to_options(cfg, std::move(names), std::vector(rvals.begin(), rvals.end()));
try {
assert_that(e.execute_prepared_with_qo(id, std::move(opts)).get()).is_rows().with_rows_ignore_order(expected);
} catch (const std::exception& e) {
BOOST_FAIL(format("execute_prepared failed: {}\n{}:{}: originally from here",
e.what(), loc.file_name(), loc.line()));
}
}
auto I(int32_t x) { return int32_type->decompose(x); }
auto F(float f) { return float_type->decompose(f); }
auto T(const char* t) { return utf8_type->decompose(t); }
auto SI(const set_type_impl::native_type& val) {
const auto int_set_type = set_type_impl::get_instance(int32_type, true);
return int_set_type->decompose(make_set_value(int_set_type, val));
};
auto ST(const set_type_impl::native_type& val) {
const auto text_set_type = set_type_impl::get_instance(utf8_type, true);
return text_set_type->decompose(make_set_value(text_set_type, val));
};
auto LI(const list_type_impl::native_type& val) {
const auto int_list_type = list_type_impl::get_instance(int32_type, true);
return int_list_type->decompose(make_list_value(int_list_type, val));
}
auto LF(const list_type_impl::native_type& val) {
const auto float_list_type = list_type_impl::get_instance(float_type, true);
return float_list_type->decompose(make_list_value(float_list_type, val));
}
auto LT(const list_type_impl::native_type& val) {
const auto text_list_type = list_type_impl::get_instance(utf8_type, true);
return text_list_type->decompose(make_list_value(text_list_type, val));
}
/// Creates a table t with int columns p, q, and r. Inserts data (i,10+i,20+i) for i = 0 to n.
void create_t_with_p_q_r(cql_test_env& e, size_t n) {
cquery_nofail(e, "create table t (p int primary key, q int, r int)");
for (size_t i = 0; i <= n; ++i) {
cquery_nofail(e, fmt::format("insert into t (p,q,r) values ({},{},{});", i, 10+i, 20+i));
}
}
} // anonymous namespace
SEASTAR_THREAD_TEST_CASE(regular_col_eq) {
do_with_cql_env_thread([](cql_test_env& e) {
create_t_with_p_q_r(e, 3);
require_rows(e, "select q from t where q=12 allow filtering", {{I(12)}});
require_rows(e, "select q from t where q=12 and q=12 allow filtering", {{I(12)}});
require_rows(e, "select q from t where q=12 and q=13 allow filtering", {});
require_rows(e, "select r from t where q=12 and p=2 allow filtering", {{I(22), I(12)}});
require_rows(e, "select p from t where q=12 and r=22 allow filtering", {{I(2), I(12), I(22)}});
require_rows(e, "select r from t where q=12 and p=2 and r=99 allow filtering", {});
cquery_nofail(e, "insert into t(p) values (100)");
require_rows(e, "select q from t where q=12 allow filtering", {{I(12)}});
auto stmt = e.prepare("select q from t where q=? allow filtering").get();
require_rows(e, stmt, {}, {I(12)}, {{I(12)}});
require_rows(e, stmt, {}, {I(99)}, {});
stmt = e.prepare("select q from t where q=:q allow filtering").get();
require_rows(e, stmt, {{"q"}}, {I(12)}, {{I(12)}});
require_rows(e, stmt, {{"q"}}, {I(99)}, {});
stmt = e.prepare("select p from t where q=? and r=? allow filtering").get();
require_rows(e, stmt, {}, {I(12), I(22)}, {{I(2), I(12), I(22)}});
require_rows(e, stmt, {}, {I(11), I(21)}, {{I(1), I(11), I(21)}});
require_rows(e, stmt, {}, {I(11), I(22)}, {});
}).get();
}
SEASTAR_THREAD_TEST_CASE(map_eq) {
do_with_cql_env_thread([](cql_test_env& e) {
cquery_nofail(e, "create table t (p int primary key, m frozen<map<int,int>>)");
cquery_nofail(e, "insert into t (p, m) values (1, {1:11, 2:12, 3:13})");
cquery_nofail(e, "insert into t (p, m) values (2, {1:21, 2:22, 3:23})");
const auto my_map_type = map_type_impl::get_instance(int32_type, int32_type, true);
const auto m1 = my_map_type->decompose(
make_map_value(my_map_type, map_type_impl::native_type({{1, 11}, {2, 12}, {3, 13}})));
require_rows(e, "select p from t where m={1:11, 2:12, 3:13} allow filtering", {{I(1), m1}});
require_rows(e, "select p from t where m={1:11, 2:12} allow filtering", {});
}).get();
}
SEASTAR_THREAD_TEST_CASE(set_eq) {
do_with_cql_env_thread([](cql_test_env& e) {
cquery_nofail(e, "create table t (p int primary key, m frozen<set<int>>)");
cquery_nofail(e, "insert into t (p, m) values (1, {11,12,13})");
cquery_nofail(e, "insert into t (p, m) values (2, {21,22,23})");
require_rows(e, "select p from t where m={21,22,23} allow filtering", {{I(2), SI({21, 22, 23})}});
require_rows(e, "select p from t where m={21,22,23,24} allow filtering", {});
}).get();
}
SEASTAR_THREAD_TEST_CASE(list_eq) {
do_with_cql_env_thread([](cql_test_env& e) {
cquery_nofail(e, "create table t (p int primary key, li frozen<list<int>>)");
cquery_nofail(e, "insert into t (p, li) values (1, [11,12,13])");
cquery_nofail(e, "insert into t (p, li) values (2, [21,22,23])");
require_rows(e, "select p from t where li=[21,22,23] allow filtering", {{I(2), LI({21, 22, 23})}});
require_rows(e, "select p from t where li=[23,22,21] allow filtering", {});
}).get();
}
SEASTAR_THREAD_TEST_CASE(list_slice) {
do_with_cql_env_thread([](cql_test_env& e) {
cquery_nofail(e, "create table t (p int primary key, li frozen<list<int>>)");
cquery_nofail(e, "insert into t (p, li) values (1, [11,12,13])");
cquery_nofail(e, "insert into t (p, li) values (2, [21,22,23])");
require_rows(e, "select li from t where li<[23,22,21] allow filtering",
{{LI({11, 12, 13})}, {LI({21, 22, 23})}});
require_rows(e, "select li from t where li>=[11,12,13] allow filtering",
{{LI({11, 12, 13})}, {LI({21, 22, 23})}});
require_rows(e, "select li from t where li>[11,12,13] allow filtering", {{LI({21, 22, 23})}});
}).get();
}
SEASTAR_THREAD_TEST_CASE(tuple_of_list) {
do_with_cql_env_thread([](cql_test_env& e) {
cquery_nofail(e, "create table t (p int, l1 frozen<list<int>>, l2 frozen<list<int>>, primary key(p,l1,l2))");
cquery_nofail(e, "insert into t (p, l1, l2) values (1, [11,12], [101,102])");
cquery_nofail(e, "insert into t (p, l1, l2) values (2, [21,22], [201,202])");
require_rows(e, "select * from t where (l1,l2)<([],[]) allow filtering", {});
require_rows(e, "select l1 from t where (l1,l2)<([20],[200]) allow filtering", {{LI({11, 12})}});
require_rows(e, "select l1 from t where (l1,l2)>=([11,12],[101,102]) allow filtering",
{{LI({11, 12})}, {LI({21, 22})}});
require_rows(e, "select l1 from t where (l1,l2)<([11,12],[101,103]) allow filtering", {{LI({11, 12})}});
}).get();
}
SEASTAR_THREAD_TEST_CASE(map_entry_eq) {
do_with_cql_env_thread([](cql_test_env& e) {
cquery_nofail(e, "create table t (p int primary key, m map<int,int>)");
cquery_nofail(e, "insert into t (p, m) values (1, {1:11, 2:12, 3:13})");
cquery_nofail(e, "insert into t (p, m) values (2, {1:21, 2:22, 3:23})");
cquery_nofail(e, "insert into t (p, m) values (3, {1:31, 2:32, 3:33})");
const auto my_map_type = map_type_impl::get_instance(int32_type, int32_type, true);
const auto m2 = my_map_type->decompose(
make_map_value(my_map_type, map_type_impl::native_type({{1, 21}, {2, 22}, {3, 23}})));
require_rows(e, "select p from t where m[1]=21 allow filtering", {{I(2), m2}});
require_rows(e, "select p from t where m[1]=21 and m[3]=23 allow filtering", {{I(2), m2}});
require_rows(e, "select p from t where m[99]=21 allow filtering", {});
require_rows(e, "select p from t where m[1]=99 allow filtering", {});
cquery_nofail(e, "delete from t where p=2");
require_rows(e, "select p from t where m[1]=21 allow filtering", {});
require_rows(e, "select p from t where m[1]=21 and m[3]=23 allow filtering", {});
const auto m3 = my_map_type->decompose(
make_map_value(my_map_type, map_type_impl::native_type({{1, 31}, {2, 32}, {3, 33}})));
require_rows(e, "select m from t where m[1]=31 allow filtering", {{m3}});
cquery_nofail(e, "update t set m={1:111} where p=3");
require_rows(e, "select p from t where m[1]=31 allow filtering", {});
require_rows(e, "select p from t where m[1]=21 allow filtering", {});
const auto m3new = my_map_type->decompose(
make_map_value(my_map_type, map_type_impl::native_type({{1, 111}})));
require_rows(e, "select p from t where m[1]=111 allow filtering", {{I(3), m3new}});
const auto stmt = e.prepare("select p from t where m[1]=:uno and m[3]=:tres allow filtering").get();
const auto m1 = my_map_type->decompose(
make_map_value(my_map_type, map_type_impl::native_type({{1, 11}, {2, 12}, {3, 13}})));
require_rows(e, stmt, {{"uno", "tres"}}, {I(11), I(13)}, {{I(1), m1}});
require_rows(e, stmt, {{"uno", "tres"}}, {I(21), I(99)}, {});
}).get();
}
SEASTAR_THREAD_TEST_CASE(regular_col_slice) {
do_with_cql_env_thread([](cql_test_env& e) {
create_t_with_p_q_r(e, 3);
require_rows(e, "select q from t where q>12 allow filtering", {{I(13)}});
require_rows(e, "select q from t where q<12 allow filtering", {{I(10)}, {I(11)}});
require_rows(e, "select q from t where q>99 allow filtering", {});
require_rows(e, "select r from t where q<12 and q>=11 allow filtering", {{I(21), I(11)}});
require_rows(e, "select * from t where q<11 and q>11 allow filtering", {});
require_rows(e, "select q from t where q<=12 and r>=21 allow filtering", {{I(11), I(21)}, {I(12), I(22)}});
cquery_nofail(e, "insert into t(p) values (4)");
require_rows(e, "select q from t where q<12 allow filtering", {{I(10)}, {I(11)}});
require_rows(e, "select q from t where q>10 allow filtering", {{I(11)}, {I(12)}, {I(13)}});
require_rows(e, "select q from t where q<12 and q>10 allow filtering", {{I(11)}});
}).get();
}
SEASTAR_THREAD_TEST_CASE(regular_col_slice_reversed) {
do_with_cql_env_thread([](cql_test_env& e) {
cquery_nofail(e, "create table t (p int, c int, primary key(p, c)) with clustering order by (c desc)");
cquery_nofail(e, "insert into t(p,c) values (1,11)");
require_rows(e, "select c from t where c>10 allow filtering", {{I(11)}});
cquery_nofail(e, "insert into t(p,c) values (1,12)");
require_rows(e, "select c from t where c>10 allow filtering", {{I(11)}, {I(12)}});
require_rows(e, "select c from t where c<100 allow filtering", {{I(11)}, {I(12)}});
}).get();
}
#if 0 // TODO: enable when supported.
SEASTAR_THREAD_TEST_CASE(regular_col_neq) {
do_with_cql_env_thread([](cql_test_env& e) {
create_t_with_p_q_r(e, 3);
require_rows(e, "select q from t where q!=10 allow filtering", {{I(11)}, {I(12)}, {I(13)}});
require_rows(e, "select q from t where q!=10 and q!=13 allow filtering", {{I(11)}, {I(12)}});
require_rows(e, "select r from t where q!=11 and r!=22 allow filtering", {{I(10), I(20)}, {I(13), I(23)}});
}).get();
}
#endif // 0
namespace {
/// The `op` argument can be one of: "<", "<=", ">", ">=", "=". Remove float args to use "!=".
future<> test_lhs_null_with_operator(sstring op) {
return do_with_cql_env_thread([op = std::move(op)] (cql_test_env& e) {
cquery_nofail(e, "CREATE TABLE cf (pk int primary key, flt float,"
" dbl double, dec decimal, b boolean, ti tinyint, si smallint,"
" i int, bi bigint, vi varint, ip inet, u uuid, tu timeuuid,"
" t time, d date, a ascii, txt text);");
cquery_nofail(e, "INSERT INTO cf (pk) VALUES (0);");
// Now we have all types of NULLs
require_rows(e, format("SELECT * FROM cf WHERE flt {} 99.9 ALLOW FILTERING;", op), {});
require_rows(e, format("SELECT * FROM cf WHERE dbl {} 99.9 ALLOW FILTERING;", op), {});
require_rows(e, format("SELECT * FROM cf WHERE dec {} 99.9 ALLOW FILTERING;", op), {});
require_rows(e, format("SELECT * FROM cf WHERE b {} true ALLOW FILTERING;", op), {});
require_rows(e, format("SELECT * FROM cf WHERE ti {} 99 ALLOW FILTERING;", op), {});
require_rows(e, format("SELECT * FROM cf WHERE si {} 999 ALLOW FILTERING;", op), {});
require_rows(e, format("SELECT * FROM cf WHERE i {} 999 ALLOW FILTERING;", op), {});
require_rows(e, format("SELECT * FROM cf WHERE bi {} 999 ALLOW FILTERING;", op), {});
require_rows(e, format("SELECT * FROM cf WHERE vi {} 999 ALLOW FILTERING;", op), {});
require_rows(e, format("SELECT * FROM cf WHERE ip {} '255.255.255.255' ALLOW FILTERING;", op), {});
require_rows(e, format("SELECT * FROM cf WHERE u {} ffffffff-e89b-12d3-a456-426655440000 ALLOW FILTERING;", op), {});
require_rows(e, format("SELECT * FROM cf WHERE tu {} ffffffff-e89b-12d3-a456-426655440000 ALLOW FILTERING;", op), {});
require_rows(e, format("SELECT * FROM cf WHERE t {} '23:59:59' ALLOW FILTERING;", op), {});
require_rows(e, format("SELECT * FROM cf WHERE d {} '2137-01-01' ALLOW FILTERING;", op), {});
require_rows(e, format("SELECT * FROM cf WHERE a {} 'Z' ALLOW FILTERING;", op), {});
require_rows(e, format("SELECT * FROM cf WHERE txt {} 'Ż' ALLOW FILTERING;", op), {});
});
}
} // anon. namespace
// This test checks that NULLs on LHS of comparison operator never evaluate to `true` (#6295).
// The expected behavior aligns with C*, but the test also ensures that NULLs are not converted
// to empty buffers somewhere along the way (since empty buffers would lexicographically
// precede anything).
SEASTAR_THREAD_TEST_CASE(null_lhs) {
test_lhs_null_with_operator("<").get();
test_lhs_null_with_operator(">").get();
}
SEASTAR_THREAD_TEST_CASE(null_rhs) {
do_with_cql_env_thread([](cql_test_env& e) {
cquery_nofail(e, "create table t (pk1 int, pk2 int, ck1 float, ck2 float, r text, primary key((pk1,pk2),ck1,ck2))");
const auto q = [&] (const char* stmt) { return e.execute_cql(stmt).get(); };
using ire = exceptions::invalid_request_exception;
using exception_predicate::message_contains;
const char* expect = "Invalid null";
cquery_nofail(e, "insert into t (pk1, pk2, ck1, ck2) values (11, 12, 21, 22)");
require_rows(e, "select * from t where pk1=0 and pk2=null", {});
BOOST_REQUIRE_EXCEPTION(q("select * from t where pk1=0 and pk2=0 and (ck1,ck2)>=(0,null)"),
ire, message_contains(expect));
require_rows(e, "select * from t where ck1=null allow filtering", {});
require_rows(e, "select * from t where r=null and ck1=null allow filtering", {});
require_rows(e, "select * from t where pk1=0 and pk2=0 and ck1<null", {});
require_rows(e, "select * from t where r>null and ck1<null allow filtering", {});
cquery_nofail(e, "insert into t(pk1,pk2,ck1,ck2) values(11,21,101,201)");
require_rows(e, "select * from t where r=null allow filtering", {});
cquery_nofail(e, "insert into t(pk1,pk2,ck1,ck2,r) values(11,21,101,202,'2')");
require_rows(e, "select * from t where r>null allow filtering", {});
require_rows(e, "select * from t where r<=null allow filtering", {});
require_rows(e, "select * from t where pk1=null allow filtering", {});
cquery_nofail(e, "create table tb (p int primary key)");
cquery_nofail(e, "insert into tb (p) values (1)");
require_rows(e, "select * from tb where p=null", {});
}).get();
}
/// Creates a tuple value from individual values.
bytes make_tuple(std::vector<data_type> types, std::vector<data_value> values) {
const auto tuple_type = tuple_type_impl::get_instance(std::move(types));
return tuple_type->decompose(
make_tuple_value(tuple_type, tuple_type_impl::native_type(std::move(values))));
}
SEASTAR_THREAD_TEST_CASE(multi_col_eq) {
do_with_cql_env_thread([](cql_test_env& e) {
cquery_nofail(e, "create table t (p int, c1 text, c2 float, primary key (p, c1, c2))");
cquery_nofail(e, "insert into t (p, c1, c2) values (1, 'one', 11);");
cquery_nofail(e, "insert into t (p, c1, c2) values (2, 'two', 12);");
require_rows(e, "select c2 from t where p=1 and (c1,c2)=('one',11)", {{F(11)}});
require_rows(e, "select c1 from t where p=1 and (c1)=('one')", {{T("one")}});
require_rows(e, "select c2 from t where p=2 and (c1,c2)=('one',11)", {});
require_rows(e, "select p from t where (c1,c2)=('two',12) allow filtering", {{I(2)}});
require_rows(e, "select c2 from t where (c1,c2)=('one',12) allow filtering", {});
require_rows(e, "select c2 from t where (c1,c2)=('two',11) allow filtering", {});
require_rows(e, "select c1 from t where (c1)=('one') allow filtering", {{T("one")}});
require_rows(e, "select c1 from t where (c1)=('x') allow filtering", {});
auto stmt = e.prepare("select p from t where (c1,c2)=:t allow filtering").get();
require_rows(e, stmt, {{"t"}}, {make_tuple({utf8_type, float_type}, {sstring("two"), 12.f})}, {{I(2)}});
require_rows(e, stmt, {{"t"}}, {make_tuple({utf8_type, float_type}, {sstring("x"), 12.f})}, {});
stmt = e.prepare("select p from t where (c1,c2)=('two',?) allow filtering").get();
require_rows(e, stmt, {}, {F(12)}, {{I(2)}});
require_rows(e, stmt, {}, {F(99)}, {});
stmt = e.prepare("select c1 from t where (c1)=? allow filtering").get();
require_rows(e, stmt, {}, {make_tuple({utf8_type}, {sstring("one")})}, {{T("one")}});
require_rows(e, stmt, {}, {make_tuple({utf8_type}, {sstring("two")})}, {{T("two")}});
require_rows(e, stmt, {}, {make_tuple({utf8_type}, {sstring("three")})}, {});
stmt = e.prepare("select c1 from t where (c1)=(:c1) allow filtering").get();
require_rows(e, stmt, {{"c1"}}, {T("one")}, {{T("one")}});
require_rows(e, stmt, {{"c1"}}, {T("two")}, {{T("two")}});
require_rows(e, stmt, {{"c1"}}, {T("three")}, {});
}).get();
}
SEASTAR_THREAD_TEST_CASE(multi_col_slice) {
do_with_cql_env_thread([](cql_test_env& e) {
cquery_nofail(e, "create table t (p int, c1 text, c2 float, primary key (p, c1, c2))");
cquery_nofail(e, "insert into t (p, c1, c2) values (1, 'a', 11);");
cquery_nofail(e, "insert into t (p, c1, c2) values (2, 'b', 2);");
cquery_nofail(e, "insert into t (p, c1, c2) values (3, 'c', 13);");
require_rows(e, "select c2 from t where (c1,c2)>('a',20) allow filtering", {{F(2)}, {F(13)}});
require_rows(e, "select p from t where (c1,c2)>=('a',20) and (c1,c2)<('b',3) allow filtering", {{I(2)}});
require_rows(e, "select * from t where (c1,c2)<('a',11) allow filtering", {});
require_rows(e, "select c1 from t where (c1,c2)<('a',12) allow filtering", {{T("a")}});
require_rows(e, "select c1 from t where (c1)>=('c') allow filtering", {{T("c")}});
require_rows(e, "select c1 from t where (c1,c2)<=('c',13) allow filtering", {{T("a")}, {T("b")}, {T("c")}});
require_rows(e, "select c1 from t where (c1,c2)>=('b',2) and (c1,c2)<=('b',2) allow filtering", {{T("b")}});
auto stmt = e.prepare("select c1 from t where (c1,c2)<? allow filtering").get();
require_rows(e, stmt, {}, {make_tuple({utf8_type, float_type}, {sstring("a"), 12.f})}, {{T("a")}});
require_rows(e, stmt, {}, {make_tuple({utf8_type, float_type}, {sstring("a"), 11.f})}, {});
stmt = e.prepare("select c1 from t where (c1,c2)<('a',:c2) allow filtering").get();
require_rows(e, stmt, {{"c2"}}, {F(12)}, {{T("a")}});
require_rows(e, stmt, {{"c2"}}, {F(11)}, {});
stmt = e.prepare("select c1 from t where (c1)>=? allow filtering").get();
require_rows(e, stmt, {}, {make_tuple({utf8_type}, {sstring("c")})}, {{T("c")}});
require_rows(e, stmt, {}, {make_tuple({utf8_type}, {sstring("x")})}, {});
stmt = e.prepare("select c1 from t where (c1)>=(:c1) allow filtering").get();
require_rows(e, stmt, {{"c1"}}, {T("c")}, {{T("c")}});
require_rows(e, stmt, {{"c1"}}, {T("x")}, {});
}).get();
}
SEASTAR_THREAD_TEST_CASE(multi_col_slice_reversed) {
do_with_cql_env_thread([](cql_test_env& e) {
cquery_nofail(e, "create table t (p int, c1 int, c2 float, primary key (p, c1, c2)) "
"with clustering order by (c1 desc, c2 asc)");
cquery_nofail(e, "insert into t(p,c1,c2) values (1,11,21)");
cquery_nofail(e, "insert into t(p,c1,c2) values (1,12,22)");
cquery_nofail(e, "insert into t(p,c1,c2) values (1,12,23)");
require_rows(e, "select c1 from t where (c1,c2)>(10,99) allow filtering", {{I(11)}, {I(12)}, {I(12)}});
require_rows(e, "select c1 from t where (c1,c2)<(12,0) allow filtering", {{I(11)}});
require_rows(e, "select c1 from t where (c1,c2)>(12,22) allow filtering", {{I(12)}});
require_rows(e, "select c1 from t where (c1)>(12) allow filtering", {});
require_rows(e, "select c1 from t where (c1)<=(12) allow filtering", {{I(11)}, {I(12)}, {I(12)}});
}).get();
}
SEASTAR_THREAD_TEST_CASE(multi_and_single_together) {
do_with_cql_env_thread([](cql_test_env& e) {
cquery_nofail(e, "create table t (p int, c1 int, c2 float, primary key (p, c1, c2)) "
"with clustering order by (c1 desc, c2 asc)");
cquery_nofail(e, "insert into t(p,c1,c2) values (1,11,21)");
cquery_nofail(e, "insert into t(p,c1,c2) values (1,12,22)");
cquery_nofail(e, "insert into t(p,c1,c2) values (1,12,23)");
const auto q = [&] (const char* stmt) { return e.execute_cql(stmt).get(); };
using ire = exceptions::invalid_request_exception;
const auto expected = exception_predicate::message_contains("Mixing");
// TODO: one day mixing single- and multi-column will become allowed, and we'll have to change these:
BOOST_REQUIRE_EXCEPTION(q("select c1 from t where c2=21 and (c1)>(10)"), ire, expected); // #7710
BOOST_REQUIRE_EXCEPTION(q("select c2 from t where (c1,c2)>(10,99) and c2>=23"), ire, expected);
}).get();
}
SEASTAR_THREAD_TEST_CASE(set_contains) {
do_with_cql_env_thread([](cql_test_env& e) {
cquery_nofail(e, "create table t (p frozen<set<int>>, c frozen<set<int>>, s set<text>, st set<int> static, primary key (p, c))");
require_rows(e, "select * from t where c contains 222 allow filtering", {});
cquery_nofail(e, "insert into t (p, c, s) values ({1}, {11, 12}, {'a1', 'b1'})");
cquery_nofail(e, "insert into t (p, c, s) values ({2}, {21, 22}, {'a2', 'b1'})");
cquery_nofail(e, "insert into t (p, c, s) values ({1, 3}, {31, 32}, {'a3', 'b3'})");
require_rows(e, "select * from t where s contains 'xyz' allow filtering", {});
require_rows(e, "select * from t where p contains 999 allow filtering", {});
require_rows(e, "select p from t where p contains 3 allow filtering", {{SI({1, 3})}});
require_rows(e, "select p from t where p contains 1 allow filtering", {{SI({1, 3})}, {SI({1})}});
require_rows(e, "select p from t where p contains null allow filtering", {});
require_rows(e, "select p from t where p contains 1 and s contains 'a1' allow filtering",
{{SI({1}), ST({"a1", "b1"})}});
require_rows(e, "select c from t where c contains 31 allow filtering", {{SI({31, 32})}});
require_rows(e, "select c from t where c contains null allow filtering", {});
require_rows(e, "select c from t where c contains 11 and p contains 1 allow filtering",
{{SI({11, 12}), SI({1})}});
require_rows(e, "select s from t where s contains 'a1' allow filtering", {{ST({"a1", "b1"})}});
require_rows(e, "select s from t where s contains 'b1' allow filtering",
{{ST({"a1", "b1"})}, {ST({"a2", "b1"})}});
require_rows(e, "select s from t where s contains null allow filtering", {});
require_rows(e, "select s from t where s contains 'b1' and s contains '' allow filtering", {});
require_rows(e, "select s from t where s contains 'b1' and p contains 4 allow filtering", {});
cquery_nofail(e, "insert into t (p, c, st) values ({4}, {41}, {104})");
require_rows(e, "select st from t where st contains 4 allow filtering", {});
require_rows(e, "select st from t where st contains 104 allow filtering", {{SI({104})}});
cquery_nofail(e, "insert into t (p, c, st) values ({4}, {42}, {105})");
require_rows(e, "select c from t where st contains 104 allow filtering", {});
require_rows(e, "select c from t where st contains 105 allow filtering",
{{SI({41}), SI({105})}, {SI({42}), SI({105})}});
cquery_nofail(e, "insert into t (p, c, st) values ({5}, {52}, {104, 105})");
require_rows(e, "select p from t where st contains 105 allow filtering",
{{SI({4}), SI({105})}, {SI({4}), SI({105})}, {SI({5}), SI({104, 105})}});
require_rows(e, "select p from t where st contains null allow filtering", {});
cquery_nofail(e, "delete from t where p={4}");
require_rows(e, "select p from t where st contains 105 allow filtering", {{SI({5}), SI({104, 105})}});
const auto stmt = e.prepare("select p from t where p contains :p allow filtering").get();
require_rows(e, stmt, {{"p"}}, {I(999)}, {});
require_rows(e, stmt, {{"p"}}, {I(1)}, {{SI({1})}, {SI({1, 3})}});
require_rows(e, stmt, {{"p"}}, {I(2)}, {{SI({2})}});
}).get();
}
SEASTAR_THREAD_TEST_CASE(list_contains) {
do_with_cql_env_thread([](cql_test_env& e) {
cquery_nofail(e, "create table t (p frozen<list<int>>, c frozen<list<int>>, ls list<int>, st list<text> static,"
"primary key(p, c))");
cquery_nofail(e, "insert into t (p, c) values ([1], [11,12,13])");
cquery_nofail(e, "insert into t (p, c, ls) values ([2], [21,22,23], [102])");
cquery_nofail(e, "insert into t (p, c, ls, st) values ([3], [21,32,33], [103], ['a', 'b'])");
cquery_nofail(e, "insert into t (p, c, st) values ([4], [41,42,43], ['a'])");
cquery_nofail(e, "insert into t (p, c) values ([4], [41,42])");
require_rows(e, "select p from t where p contains 222 allow filtering", {});
require_rows(e, "select p from t where c contains 222 allow filtering", {});
require_rows(e, "select p from t where ls contains 222 allow filtering", {});
require_rows(e, "select p from t where st contains 'xyz' allow filtering", {});
require_rows(e, "select p from t where p contains 1 allow filtering", {{LI({1})}});
require_rows(e, "select p from t where p contains 4 allow filtering", {{LI({4})}, {LI({4})}});
require_rows(e, "select p from t where p contains null allow filtering", {});
require_rows(e, "select c from t where c contains 22 allow filtering", {{LI({21,22,23})}});
require_rows(e, "select c from t where c contains 21 allow filtering", {{LI({21,22,23})}, {LI({21,32,33})}});
require_rows(e, "select c from t where c contains null allow filtering", {});
require_rows(e, "select c from t where c contains 21 and ls contains 102 allow filtering",
{{LI({21,22,23}), LI({102})}});
require_rows(e, "select ls from t where ls contains 102 allow filtering", {{LI({102})}});
require_rows(e, "select ls from t where ls contains null allow filtering", {});
require_rows(e, "select st from t where st contains 'a' allow filtering",
{{LT({"a"})}, {LT({"a"})}, {LT({"a", "b"})}});
require_rows(e, "select st from t where st contains null allow filtering", {});
require_rows(e, "select st from t where st contains 'b' allow filtering", {{LT({"a", "b"})}});
cquery_nofail(e, "delete from t where p=[2]");
require_rows(e, "select c from t where c contains 21 allow filtering", {{LI({21,32,33})}});
}).get();
}
SEASTAR_THREAD_TEST_CASE(map_contains) {
do_with_cql_env_thread([](cql_test_env& e) {
cquery_nofail(e, "create table t (p frozen<map<int,int>>, c frozen<map<int,int>>, m map<int,int>,"
"s map<int,int> static, primary key(p, c))");
cquery_nofail(e, "insert into t (p, c, m) values ({1:1}, {10:10}, {1:11, 2:12})");
require_rows(e, "select * from t where m contains 21 allow filtering", {});
cquery_nofail(e, "insert into t (p, c, m) values ({2:2}, {20:20}, {1:21, 2:12})");
cquery_nofail(e, "insert into t (p, c) values ({3:3}, {30:30})");
cquery_nofail(e, "insert into t (p, c, s) values ({3:3}, {31:31}, {3:100})");
cquery_nofail(e, "insert into t (p, c, s) values ({4:4}, {40:40}, {4:100})");
const auto my_map_type = map_type_impl::get_instance(int32_type, int32_type, true);
const auto p3 = my_map_type->decompose(make_map_value(my_map_type, map_type_impl::native_type({{3, 3}})));
require_rows(e, "select p from t where p contains 3 allow filtering", {{p3}, {p3}});
const auto p1 = my_map_type->decompose(make_map_value(my_map_type, map_type_impl::native_type({{1, 1}})));
const auto p2 = my_map_type->decompose(make_map_value(my_map_type, map_type_impl::native_type({{2, 2}})));
const auto p4 = my_map_type->decompose(make_map_value(my_map_type, map_type_impl::native_type({{4, 4}})));
require_rows(e, "select p from t where p contains null allow filtering", {});
const auto c4 = my_map_type->decompose(make_map_value(my_map_type, map_type_impl::native_type({{40, 40}})));
require_rows(e, "select c from t where c contains 40 allow filtering", {{c4}});
const auto m2 = my_map_type->decompose(
make_map_value(my_map_type, map_type_impl::native_type({{1, 21}, {2, 12}})));
require_rows(e, "select m from t where m contains 21 allow filtering", {{m2}});
const auto m1 = my_map_type->decompose(
make_map_value(my_map_type, map_type_impl::native_type({{1, 11}, {2, 12}})));
require_rows(e, "select m from t where m contains 11 allow filtering", {{m1}});
require_rows(e, "select m from t where m contains 12 allow filtering", {{m1}, {m2}});
require_rows(e, "select m from t where m contains null allow filtering", {});
require_rows(e, "select m from t where m contains 11 and m contains 12 allow filtering", {{m1}});
cquery_nofail(e, "delete from t where p={2:2}");
require_rows(e, "select m from t where m contains 12 allow filtering", {{m1}});
const auto s3 = my_map_type->decompose(
make_map_value(my_map_type, map_type_impl::native_type({{3, 100}})));
const auto s4 = my_map_type->decompose(
make_map_value(my_map_type, map_type_impl::native_type({{4, 100}})));
require_rows(e, "select s from t where s contains 100 allow filtering", {{s3}, {s3}, {s4}});
}).get();
}
SEASTAR_THREAD_TEST_CASE(contains_key) {
do_with_cql_env_thread([](cql_test_env& e) {
cquery_nofail(e,
"create table t (p frozen<map<int,int>>, c frozen<map<text,int>>, m map<int,int>, "
"s map<int,text> static, primary key(p, c))");
cquery_nofail(e, "insert into t (p,c,m) values ({1:11, 2:12}, {'el':11, 'twel':12}, {11:11, 12:12})");
require_rows(e, "select * from t where p contains key 3 allow filtering", {});
require_rows(e, "select * from t where c contains key 'x' allow filtering", {});
require_rows(e, "select * from t where m contains key 3 allow filtering", {});
require_rows(e, "select * from t where s contains key 3 allow filtering", {});
cquery_nofail(e, "insert into t (p,c,m) values ({3:33}, {'th':33}, {11:33})");
const auto int_map_type = map_type_impl::get_instance(int32_type, int32_type, true);
const auto m1 = int_map_type->decompose(
make_map_value(int_map_type, map_type_impl::native_type({{11, 11}, {12, 12}})));
const auto m3 = int_map_type->decompose(make_map_value(int_map_type, map_type_impl::native_type({{11, 33}})));
require_rows(e, "select m from t where m contains key 12 allow filtering", {{m1}});
require_rows(e, "select m from t where m contains key 11 allow filtering", {{m1}, {m3}});
require_rows(e, "select m from t where m contains key null allow filtering", {});
const auto text_map_type = map_type_impl::get_instance(utf8_type, int32_type, true);
const auto c1 = text_map_type->decompose(
make_map_value(text_map_type, map_type_impl::native_type({{"el", 11}, {"twel", 12}})));
require_rows(e, "select c from t where c contains key 'el' allow filtering", {{c1}});
require_rows(e, "select c from t where c contains key 'twel' allow filtering", {{c1}});
const auto c3 = text_map_type->decompose(
make_map_value(text_map_type, map_type_impl::native_type({{"th", 33}})));
require_rows(e, "select c from t where c contains key null allow filtering", {});
const auto p3 = int_map_type->decompose(make_map_value(int_map_type, map_type_impl::native_type({{3, 33}})));
require_rows(e, "select p from t where p contains key 3 allow filtering", {{p3}});
require_rows(e, "select p from t where p contains key 3 and m contains key null allow filtering", {});
const auto p1 = int_map_type->decompose(
make_map_value(int_map_type, map_type_impl::native_type({{1, 11}, {2, 12}})));
require_rows(e, "select p from t where p contains key null allow filtering", {});
cquery_nofail(e, "insert into t (p,c) values ({4:44}, {'aaaa':44})");
require_rows(e, "select m from t where m contains key 12 allow filtering", {{m1}});
cquery_nofail(e, "delete from t where p={1:11, 2:12}");
require_rows(e, "select m from t where m contains key 12 allow filtering", {});
require_rows(e, "select s from t where s contains key 55 allow filtering", {});
cquery_nofail(e, "insert into t (p,c,s) values ({5:55}, {'aaaa':55}, {55:'aaaa'})");
cquery_nofail(e, "insert into t (p,c,s) values ({5:55}, {'aaa':55}, {55:'aaaa'})");
const auto int_text_map_type = map_type_impl::get_instance(int32_type, utf8_type, true);
const auto s5 = int_text_map_type->decompose(
make_map_value(int_text_map_type, map_type_impl::native_type({{55, "aaaa"}})));
require_rows(e, "select s from t where s contains key 55 allow filtering", {{s5}, {s5}});
require_rows(e, "select s from t where s contains key 55 and s contains key null allow filtering", {});
const auto c51 = text_map_type->decompose(
make_map_value(text_map_type, map_type_impl::native_type({{"aaaa", 55}})));
const auto c52 = text_map_type->decompose(
make_map_value(text_map_type, map_type_impl::native_type({{"aaa", 55}})));
require_rows(e, "select c from t where s contains key 55 allow filtering", {{c51, s5}, {c52, s5}});
cquery_nofail(e, "insert into t (p,c,s) values ({6:66}, {'bbb':66}, {66:'bbbb', 55:'bbbb'})");
const auto p5 = int_map_type->decompose(make_map_value(int_map_type, map_type_impl::native_type({{5, 55}})));
const auto p6 = int_map_type->decompose(make_map_value(int_map_type, map_type_impl::native_type({{6, 66}})));
const auto s6 = int_text_map_type->decompose(
make_map_value(int_text_map_type, map_type_impl::native_type({{55, "bbbb"}, {66, "bbbb"}})));
require_rows(e, "select p from t where s contains key 55 allow filtering", {{p5, s5}, {p5, s5}, {p6, s6}});
const auto stmt = e.prepare("select p from t where s contains key :k allow filtering").get();
require_rows(e, stmt, {{"k"}}, {I(55)}, {{p5, s5}, {p5, s5}, {p6, s6}});
require_rows(e, stmt, {{"k"}}, {I(999)}, {});
}).get();
}
SEASTAR_THREAD_TEST_CASE(like) {
do_with_cql_env_thread([](cql_test_env& e) {
cquery_nofail(e, "create table t (pk text, ck1 text, ck2 text, r text, s text static, primary key (pk, ck1, ck2))");
require_rows(e, "select * from t where pk like 'a' allow filtering", {});
cquery_nofail(e, "insert into t (pk, ck1, ck2) values ('pa', 'c1a', 'c2a');");
require_rows(e, "select * from t where pk like 'a' allow filtering", {});
require_rows(e, "select pk from t where pk like '_a' allow filtering", {{T("pa")}});
require_rows(e, "select pk from t where pk like '_a' and ck1 like '' allow filtering", {});
require_rows(e, "select pk from t where r like '_a' allow filtering", {});
require_rows(e, "select pk from t where pk like '_a' and ck2 like '_2%' allow filtering",
{{T("pa"), T("c2a")}});
cquery_nofail(e, "insert into t (pk, ck1, ck2, r, s) values ('pb', 'c1b', 'c2b', 'rb', 'sb');");
require_rows(e, "select pk from t where pk like '_a' allow filtering", {{T("pa")}});
require_rows(e, "select r from t where r like '_a' allow filtering", {});
require_rows(e, "select r from t where r like '_b' allow filtering", {{T("rb")}});
cquery_nofail(e, "insert into t (pk, ck1, ck2, r) values ('pb', 'c1ba', 'c2ba', 'rba');");
require_rows(e, "select r from t where r like 'rb%' allow filtering", {{T("rb")}, {T("rba")}});
require_rows(e, "select pk from t where s like '_b%' allow filtering",
{{T("pb"), T("sb")}, {T("pb"), T("sb")}});
cquery_nofail(e, "insert into t (pk, ck1, ck2, r, s) values ('pc', 'c1c', 'c2c', 'rc', 'sc');");
require_rows(e, "select s from t where s like 's%' allow filtering", {{T("sb")}, {T("sb")}, {T("sc")}});
require_rows(e, "select r from t where ck1 like '' allow filtering", {});
require_rows(e, "select ck1 from t where ck1 like '%c' allow filtering", {{T("c1c")}});
require_rows(e, "select ck2 from t where ck2 like 'c%' allow filtering",
{{T("c2a")}, {T("c2b")}, {T("c2ba")}, {T("c2c")}});
require_rows(e, "select * from t where ck1 like '' and ck2 like '_2a' allow filtering", {});
require_rows(e, "select r from t where r='rb' and ck2 like 'c2_' allow filtering", {{T("rb"), T("c2b")}});
const auto stmt = e.prepare("select ck1 from t where ck1 like ? allow filtering").get();
require_rows(e, stmt, {}, {T("%c")}, {{T("c1c")}});
require_rows(e, stmt, {}, {T("%xyxyz")}, {});
}).get();
}
SEASTAR_THREAD_TEST_CASE(scalar_in) {
do_with_cql_env_thread([](cql_test_env& e) {
cquery_nofail(e, "create table t (p int, c int, r float, s text static, primary key (p, c))");
require_rows(e, "select c from t where c in (11,12,13) allow filtering", {});
cquery_nofail(e, "insert into t(p,c) values (1,11)");
require_rows(e, "select c from t where c in (11,12,13) allow filtering", {{I(11)}});
cquery_nofail(e, "insert into t(p,c,r) values (1,11,21)");
cquery_nofail(e, "insert into t(p,c,r) values (2,12,22)");
cquery_nofail(e, "insert into t(p,c,r) values (3,13,23)");
cquery_nofail(e, "insert into t(p,c,r) values (4,14,24)");
cquery_nofail(e, "insert into t(p,c,r,s) values (4,15,24,'34')");
cquery_nofail(e, "insert into t(p,c,r,s) values (5,15,25,'35')");
require_rows(e, "select c from t where c in (11,12,13) allow filtering", {{I(11)}, {I(12)}, {I(13)}});
require_rows(e, "select c from t where c in (11) allow filtering", {{I(11)}});
require_rows(e, "select c from t where c in (999) allow filtering", {});
require_rows(e, "select c from t where c in (11,999) allow filtering", {{I(11)}});
require_rows(e, "select c from t where c in (11,12,13) and r in (21,24) allow filtering", {{I(11), F(21)}});
require_rows(e, "select c from t where c in (11,12,13) and r in (21,22) allow filtering",
{{I(11), F(21)}, {I(12), F(22)}});
require_rows(e, "select r from t where r in (999) allow filtering", {});
require_rows(e, "select r from t where r in (1,2,3) allow filtering", {});
require_rows(e, "select r from t where r in (22,25) allow filtering", {{F(22)}, {F(25)}});
require_rows(e, "select r from t where r in (22,25) and c < 20 allow filtering",
{{F(22), I(12)}, {F(25), I(15)}});
require_rows(e, "select r from t where r in (22,25) and s>='25' allow filtering", {{F(25), T("35")}});
require_rows(e, "select r from t where r in (25) and s>='25' allow filtering", {{F(25), T("35")}});
require_rows(e, "select r from t where r in (25) allow filtering", {{F(25)}});
cquery_nofail(e, "delete from t where p=2");
require_rows(e, "select r from t where r in (22,25) allow filtering", {{F(25)}});
require_rows(e, "select s from t where s in ('34','35') allow filtering", {{T("34")}, {T("34")}, {T("35")}});
require_rows(e, "select s from t where s in ('34','35','999') allow filtering",
{{T("34")}, {T("34")}, {T("35")}});
require_rows(e, "select s from t where s in ('34') allow filtering", {{T("34")}, {T("34")}});
require_rows(e, "select s from t where s in ('34','35') and r=24 allow filtering",
{{T("34"), F(24)}, {T("34"), F(24)}});
const auto stmt = e.prepare("select r from t where r in ? allow filtering").get();
require_rows(e, stmt, {}, {LF({99.f, 88.f, 77.f})}, {});
require_rows(e, stmt, {}, {LF({21.f})}, {{F(21)}});
require_rows(e, stmt, {}, {LF({21.f, 22.f, 23.f})}, {{F(21)}, {F(23)}});
require_rows(e, stmt, {}, {LF({24.f, 25.f})}, {{F(24)}, {F(24)}, {F(25)}});
require_rows(e, stmt, {}, {LF({25.f, data_value::make_null(float_type)})}, {{F(25)}});
require_rows(e, stmt, {}, {LF({99.f, data_value::make_null(float_type)})}, {});
}).get();
}
SEASTAR_THREAD_TEST_CASE(list_in) {
do_with_cql_env_thread([](cql_test_env& e) {
cquery_nofail(e, "create table t (p frozen<list<int>>, c frozen<list<int>>, primary key(p, c))");
cquery_nofail(e, "insert into t (p, c) values ([1], [11,12,13])");
cquery_nofail(e, "insert into t (p, c) values ([2], [21,22,23])");
cquery_nofail(e, "insert into t (p, c) values ([3], [31,32,33])");
cquery_nofail(e, "insert into t (p, c) values ([4], [41,42,43])");
cquery_nofail(e, "insert into t (p, c) values ([4], [])");
cquery_nofail(e, "insert into t (p, c) values ([5], [51,52,53])");
require_rows(e, "select c from t where c in ([11,12],[11,13]) allow filtering", {});
require_rows(e, "select c from t where c in ([11,12,13],[11,13,12]) allow filtering", {{LI({11,12,13})}});
require_rows(e, "select c from t where c in ([11,12,13],[11,13,12],[41,42,43]) allow filtering",
{{LI({11,12,13})}, {LI({41,42,43})}});
require_rows(e, "select c from t where p in ([1],[2],[4]) and c in ([11,12,13], [41,42,43])",
{{LI({11,12,13})}, {LI({41,42,43})}});
require_rows(e, "select c from t where c in ([],[11,13,12]) allow filtering", {{LI({})}});
}).get();
}
SEASTAR_THREAD_TEST_CASE(set_in) {
do_with_cql_env_thread([](cql_test_env& e) {
cquery_nofail(e, "create table t (p frozen<set<int>>, c frozen<set<int>>, r text, primary key (p, c))");
require_rows(e, "select * from t where c in ({222}) allow filtering", {});
cquery_nofail(e, "insert into t (p, c) values ({1,11}, {21,201})");
cquery_nofail(e, "insert into t (p, c, r) values ({1,11}, {22,202}, '2')");
require_rows(e, "select * from t where c in ({222}, {21}) allow filtering", {});
require_rows(e, "select c from t where c in ({222}, {21,201}) allow filtering", {{SI({21, 201})}});
require_rows(e, "select c from t where c in ({22,202}, {21,201}) allow filtering", {{SI({21, 201})}, {SI({22, 202})}});
require_rows(e, "select c from t where c in ({222}, {21,201}) and r='' allow filtering", {});
require_rows(e, "select c from t where c in ({222}, {21,201}) and r='x' allow filtering", {});
require_rows(e, "select c from t where c in ({22,202}, {21,201}) and r='2' allow filtering",
{{SI({22, 202}), T("2")}});
require_rows(e, "select c from t where c in ({22,202}, {21,201}) and p in ({1,11}, {222})",
{{SI({21, 201})}, {SI({22, 202})}});
}).get();
}
SEASTAR_THREAD_TEST_CASE(map_in) {
do_with_cql_env_thread([](cql_test_env& e) {
cquery_nofail(e, "create table t (p frozen<map<int,int>>, c frozen<map<int,int>>, r int, primary key(p, c))");
cquery_nofail(e, "insert into t (p, c) values ({1:1}, {10:10})");
cquery_nofail(e, "insert into t (p, c, r) values ({1:1}, {10:10,11:11}, 12)");
require_rows(e, "select * from t where c in ({10:11},{10:11},{11:11}) allow filtering", {});
const auto my_map_type = map_type_impl::get_instance(int32_type, int32_type, true);
const auto c1a = my_map_type->decompose(make_map_value(my_map_type, map_type_impl::native_type({{10, 10}})));
require_rows(e, "select c from t where c in ({10:11}, {10:10}, {11:11}) allow filtering", {{c1a}});
const auto c1b = my_map_type->decompose(
make_map_value(my_map_type, map_type_impl::native_type({{10, 10}, {11, 11}})));
require_rows(e, "select c from t where c in ({10:11}, {10:10}, {10:10,11:11}) allow filtering",
{{c1a}, {c1b}});
require_rows(e, "select c from t where c in ({10:11}, {10:10}, {10:10,11:11}) and r=12 allow filtering",
{{c1b, I(12)}});
require_rows(e, "select c from t where c in ({10:11}, {10:10}, {10:10,11:11}) and p in ({1:1},{2:2})",
{{c1a}, {c1b}});
}).get();
}
SEASTAR_THREAD_TEST_CASE(multi_col_in) {
do_with_cql_env_thread([](cql_test_env& e) {
cquery_nofail(e, "create table t (pk int, ck1 int, ck2 float, r text, primary key (pk, ck1, ck2))");
require_rows(e, "select ck1 from t where (ck1,ck2) in ((11,21),(12,22)) allow filtering", {});
cquery_nofail(e, "insert into t(pk,ck1,ck2) values (1,11,21)");
require_rows(e, "select ck1 from t where (ck1,ck2) in ((11,21),(12,22)) allow filtering", {{I(11)}});
require_rows(e, "select ck1 from t where (ck1,ck2) in ((11,21)) allow filtering", {{I(11)}});
cquery_nofail(e, "insert into t(pk,ck1,ck2) values (2,12,22)");
require_rows(e, "select ck1 from t where (ck1,ck2) in ((11,21),(12,22)) allow filtering", {{I(11)}, {I(12)}});
cquery_nofail(e, "insert into t(pk,ck1,ck2) values (3,13,23)");
require_rows(e, "select ck1 from t where (ck1,ck2) in ((11,21),(12,22)) allow filtering", {{I(11)}, {I(12)}});
require_rows(e, "select ck1 from t where (ck1,ck2) in ((13,23)) allow filtering", {{I(13)}});
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)}});
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").get();
auto bound_tuples = [] (std::vector<std::tuple<int32_t, float>> tuples) {
const auto tuple_type = tuple_type_impl::get_instance({int32_type, float_type});
const auto list_type = list_type_impl::get_instance(tuple_type, true);
const auto tvals = tuples | std::views::transform([&] (const std::tuple<int32_t, float>& t) {
return make_tuple_value(tuple_type, tuple_type_impl::native_type({std::get<0>(t), std::get<1>(t)}));
});
return list_type->decompose(
make_list_value(list_type, std::vector<data_value>(tvals.begin(), tvals.end())));
};
require_rows(e, stmt, {}, {bound_tuples({{11, 21}})}, {{I(11)}});
require_rows(e, stmt, {}, {bound_tuples({{11, 21}, {11, 99}})}, {{I(11)}});
require_rows(e, stmt, {}, {bound_tuples({{12, 22}})}, {{I(12)}});
require_rows(e, stmt, {}, {bound_tuples({{13, 13}, {12, 22}})}, {{I(12)}});
require_rows(e, stmt, {}, {bound_tuples({{12, 21}})}, {});
require_rows(e, stmt, {}, {bound_tuples({{12, 21}, {12, 21}, {13, 21}, {14, 21}})}, {});
stmt = e.prepare("select ck1 from t where (ck1,ck2) in (?) allow filtering").get();
auto tpl = [] (int32_t e1, float e2) {
return make_tuple({int32_type, float_type}, {e1, e2});
};
require_rows(e, stmt, {}, {tpl(11, 21)}, {{I(11)}});
require_rows(e, stmt, {}, {tpl(12, 22)}, {{I(12)}});
require_rows(e, stmt, {}, {tpl(12, 21)}, {});
stmt = e.prepare("select ck1 from t where (ck1,ck2) in (:t1,:t2) allow filtering").get();
require_rows(e, stmt, {{"t1", "t2"}}, {tpl(11, 21), tpl(12, 22)}, {{I(11)}, {I(12)}});
require_rows(e, stmt, {{"t1", "t2"}}, {tpl(11, 21), tpl(11, 21)}, {{I(11)}});
require_rows(e, stmt, {{"t1", "t2"}}, {tpl(11, 21), tpl(99, 99)}, {{I(11)}});
require_rows(e, stmt, {{"t1", "t2"}}, {tpl(9, 9), tpl(99, 99)}, {});
// Parsing error:
// stmt = e.prepare("select ck1 from t where (ck1,ck2) in ((13,23),:p1)").get();
stmt = e.prepare("select ck1 from t where (ck1,ck2) in ((13,23),(?,?)) allow filtering").get();
require_rows(e, stmt, {}, {I(0), F(0)}, {{I(13)}});
require_rows(e, stmt, {}, {I(11), F(21)}, {{I(11)}, {I(13)}});
}).get();
}
SEASTAR_THREAD_TEST_CASE(bounds) {
do_with_cql_env_thread([](cql_test_env& e) {
cquery_nofail(e, "create table t (p int, c int, primary key (p, c))");
cquery_nofail(e, "insert into t (p, c) values (1, 11);");
cquery_nofail(e, "insert into t (p, c) values (2, 12);");
cquery_nofail(e, "insert into t (p, c) values (3, 13);");
require_rows(e, "select p from t where p=1 and c > 10", {{I(1)}});
require_rows(e, "select p from t where p=1 and c = 11", {{I(1)}});
require_rows(e, "select p from t where p=1 and (c) >= (10)", {{I(1)}});
require_rows(e, "select p from t where p=1 and (c) = (11)", {{I(1)}});
require_rows(e, "select c from t where p in (1,2,3) and c > 11 and c < 13", {{I(12)}});
require_rows(e, "select c from t where p in (1,2,3) and c >= 11 and c < 13", {{I(11)}, {I(12)}});
auto stmt = e.prepare("select c from t where p in (1,2,3) and c >= 11 and c < ?").get();
require_rows(e, stmt, {}, {I(13)}, {{I(11)}, {I(12)}});
require_rows(e, stmt, {}, {I(10)}, {});
stmt = e.prepare("select c from t where p in (1,2,3) and (c) < ?").get();
require_rows(e, stmt, {}, {make_tuple({int32_type}, {13})}, {{I(11)}, {I(12)}});
require_rows(e, stmt, {}, {make_tuple({int32_type}, {11})}, {});
}).get();
}
SEASTAR_THREAD_TEST_CASE(bounds_reversed) {
do_with_cql_env_thread([](cql_test_env& e) {
cquery_nofail(e, "create table t (pk int, ck1 int, ck2 int, primary key (pk, ck1, ck2)) "
"with clustering order by (ck1 asc, ck2 desc)");
cquery_nofail(e, "insert into t (pk,ck1,ck2) values (1,11,21);");
cquery_nofail(e, "insert into t (pk,ck1,ck2) values (2,12,22);");
require_rows(e, "select pk from t where pk=1 and ck1>10", {{I(1)}});
require_rows(e, "select pk from t where pk=1 and ck1=11", {{I(1)}});
require_rows(e, "select pk from t where pk=1 and (ck1)>=(10)", {{I(1)}});
require_rows(e, "select pk from t where pk=1 and (ck1,ck2)>=(10,30)", {{I(1)}});
require_rows(e, "select pk from t where pk=1 and (ck1,ck2)>=(10,30) and (ck1)<(20)", {{I(1)}});
require_rows(e, "select pk from t where pk=1 and (ck1,ck2)>=(10,20) and (ck1,ck2)<(20,21)", {{I(1)}});
require_rows(e, "select pk from t where pk=1 and (ck1,ck2)>=(10,20) and (ck1,ck2)<=(11,20)", {});
require_rows(e, "select pk from t where pk=1 and (ck1)=(11)", {{I(1)}});
require_rows(e, "select pk from t where pk=1 and (ck1,ck2)=(11,21)", {{I(1)}});
cquery_nofail(e, "insert into t (pk,ck1,ck2) values (2,12,23);");
require_rows(e, "select ck1 from t where pk in (1,2,3) and ck1=12 and ck2<23", {{I(12)}});
require_rows(e, "select ck1 from t where pk in (1,2,3) and ck1=12 and ck2<24", {{I(12)}, {I(12)}});
}).get();
}
SEASTAR_THREAD_TEST_CASE(multi_eq_on_primary) {
do_with_cql_env_thread([](cql_test_env& e) {
cquery_nofail(e, "create table t (p int, c int, primary key (p, c))");
cquery_nofail(e, "insert into t (p, c) values (1, 11);");
cquery_nofail(e, "insert into t (p, c) values (2, 12);");
cquery_nofail(e, "insert into t (p, c) values (3, 13);");
require_rows(e, "select p from t where p=1 and p=1", {{I(1)}});
require_rows(e, "select p from t where p=1 and p=2", {});
require_rows(e, "select c from t where c=11 and c=11 allow filtering", {{I(11)}});
require_rows(e, "select c from t where c=11 and c=999 allow filtering", {});
cquery_nofail(e, "create table t2 (pk1 int, pk2 int, ck1 int, ck2 int, primary key ((pk1, pk2), ck1, ck2))");
cquery_nofail(e, "insert into t2 (pk1, pk2, ck1, ck2) values (1, 12, 21, 22);");
cquery_nofail(e, "insert into t2 (pk1, pk2, ck1, ck2) values (1, 12, 210, 220);");
require_rows(e, "select pk1 from t2 where pk1=1 and pk1=1 and pk2=12", {{I(1)}, {I(1)}});
require_rows(e, "select pk1 from t2 where pk1=0 and pk1=1 and pk2=12", {});
require_rows(e, "select pk1 from t2 where pk1=1 and pk2=12 and ck1=21 and ck1=21", {{I(1)}});
require_rows(e, "select pk1 from t2 where pk1=1 and pk2=12 and ck1=21 and ck1=21 and ck1=21", {{I(1)}});
require_rows(e, "select pk1 from t2 where pk1=1 and pk2=12 and ck1=21 and ck1=210", {});
require_rows(e, "select pk1 from t2 where pk1=1 and pk2=12 and ck1=21 and ck1=210 and ck1=210", {});
}).get();
}
SEASTAR_THREAD_TEST_CASE(token) {
do_with_cql_env_thread([](cql_test_env& e) {
cquery_nofail(e, "create table t (p int, q int, r int, primary key ((p, q)))");
cquery_nofail(e, "insert into t (p,q,r) values (1,11,101);");
cquery_nofail(e, "insert into t (p,q,r) values (2,12,102);");
cquery_nofail(e, "insert into t (p,q,r) values (3,13,103);");
require_rows(e, "select p from t where token(p,q) = token(1,11)", {{I(1)}});
require_rows(e, "select p from t where token(p,q) >= token(1,11) and token(p,q) <= token(1,11)", {{I(1)}});
// WARNING: the following two cases rely on having no token collisions, which cannot be guaranteed.
// Keeping them because (absent collisions) they complete code coverage, guarding against
// hard-to-trigger bugs.
require_rows(e, "select p from t where token(p,q) = token(1,11) and token(p,q) = token(2,12)", {});
require_rows(e, "select p from t where token(p,q) <= token(1,11) and token(p,q) = token(2,12)", {{I(2)}});
require_rows(e, "select p from t where token(p,q) > token(9,9) and token(p,q) < token(9,9)", {});
const auto min_bounds = format("select p from t where token(p,q) > {:d} and token(p,q) < {:d}",
std::numeric_limits<int64_t>::min(), std::numeric_limits<int64_t>::min());
require_rows(e, min_bounds, {{I(1)}, {I(2)}, {I(3)}});
require_rows(e, "select p from t where token(p,q) <= token(1,11) and r<102 allow filtering",
{{I(1), I(101)}});
require_rows(e, "select p from t where token(p,q) = token(2,12) and r<102 allow filtering", {});
const auto stmt = e.prepare("select p from t where token(p,q) = token(1,?)").get();
require_rows(e, stmt, {}, {I(11)}, {{I(1)}});
require_rows(e, stmt, {}, {I(10)}, {});
const auto q = [&] (const char* stmt) { return e.execute_cql(stmt).get(); };
using ire = exceptions::invalid_request_exception;
using exception_predicate::message_contains;
const char* expect = "cannot be restricted by both a normal relation and a token relation";
BOOST_REQUIRE_EXCEPTION(q("select p from t where p = 0 and token(p, q) <= token(1,11)"), ire, message_contains(expect));
BOOST_REQUIRE_EXCEPTION(q("select p from t where token(p, q) <= token(1,11) and p = 0"), ire, message_contains(expect));
BOOST_REQUIRE_EXCEPTION(q("select p from t where p in (0,1) and token(p, q) <= token(1,11)"), ire, message_contains(expect));
BOOST_REQUIRE_EXCEPTION(q("select p from t where token(p, q) <= token(1,11) and p in (0,1)"), ire, message_contains(expect));
BOOST_REQUIRE_EXCEPTION(q("select p from t where p = 0 and q = 0 and token(p, q) <= token(1,11)"), ire, message_contains(expect));
BOOST_REQUIRE_EXCEPTION(q("select p from t where token(p, q) <= token(1,11) and p = 0 and q = 0"), ire, message_contains(expect));
}).get();
}
SEASTAR_THREAD_TEST_CASE(tuples) {
do_with_cql_env_thread([](cql_test_env& e) {
cquery_nofail(e, "create table t (p int primary key, q tuple<int>, r tuple<int,int>)");
cquery_nofail(e, "insert into t (p,q,r) values (1,(1),(1,1));");
cquery_nofail(e, "insert into t (p,q,r) values (2,(2),(2,2));");
require_rows(e, "select r from t where r=(1,1) allow filtering",
{{make_tuple({int32_type, int32_type}, {1, 1})}});
require_rows(e, "select r from t where r<(2,2) allow filtering",
{{make_tuple({int32_type, int32_type}, {1, 1})}});
require_rows(e, "select r from t where r<(1,99) allow filtering",
{{make_tuple({int32_type, int32_type}, {1, 1})}});
require_rows(e, "select r from t where r<=(2, 2) allow filtering",
{{make_tuple({int32_type, int32_type}, {1, 1})}, {make_tuple({int32_type, int32_type}, {2, 2})}});
require_rows(e, "select q from t where q=(1) allow filtering", {{make_tuple({int32_type}, {1})}});
require_rows(e, "select q from t where q>=(1) allow filtering",
{{make_tuple({int32_type}, {1})}, {make_tuple({int32_type}, {2})}});
require_rows(e, "select q from t where q>=(2) allow filtering", {{make_tuple({int32_type}, {2})}});
require_rows(e, "select q from t where q>(99) allow filtering", {});
}).get();
}
SEASTAR_THREAD_TEST_CASE(strict_allow_filtering) {
auto cfg = make_shared<db::config>();
cfg->strict_allow_filtering(db::tri_mode_restriction_t::mode::TRUE);
do_with_cql_env_thread([](cql_test_env& e) {
cquery_nofail(e, "create table t (p int, c int, primary key (p,c))");
require_rows(e, "select p from t where c>0 allow filtering", {});
BOOST_REQUIRE_EXCEPTION(
e.execute_cql("select p from t where c>0").get(),
exceptions::invalid_request_exception,
exception_predicate::message_contains("use ALLOW FILTERING"));
}, cfg).get();
}
SEASTAR_THREAD_TEST_CASE(nonstrict_allow_filtering) {
auto cfg = make_shared<db::config>();
cfg->strict_allow_filtering(db::tri_mode_restriction_t::mode::FALSE);
do_with_cql_env_thread([](cql_test_env& e) {
cquery_nofail(e, "create table t (p int, c int, primary key (p,c))");
require_rows(e, "select p from t where c>0 allow filtering", {});
require_rows(e, "select p from t where c>0", {});
}, cfg).get();
}
SEASTAR_THREAD_TEST_CASE(warn_strict_allow_filtering) {
auto cfg = make_shared<db::config>();
cfg->strict_allow_filtering(db::tri_mode_restriction_t::mode::WARN);
do_with_cql_env_thread([](cql_test_env& e) {
cquery_nofail(e, "create table t (p int, c int, primary key (p,c))");
require_rows(e, "select p from t where c>0 allow filtering", {});
require_rows(e, "select p from t where c>0", {});
}, cfg).get();
}
SEASTAR_THREAD_TEST_CASE(strict_allow_filtering_live_update) {
auto cfg = make_shared<db::config>();
cfg->strict_allow_filtering(db::tri_mode_restriction_t::mode::FALSE);
do_with_cql_env_thread([&] (cql_test_env& e) {
cquery_nofail(e, "create table t (p int, c int, primary key (p,c))");
const char* stmt = "select p from t where c>0";
require_rows(e, stmt, {});
cfg->strict_allow_filtering(db::tri_mode_restriction_t::mode::TRUE);
BOOST_REQUIRE_EXCEPTION(
e.execute_cql(stmt).get(),
exceptions::invalid_request_exception,
exception_predicate::message_contains("use ALLOW FILTERING"));
}, cfg).get();
}
// Ok - only view primary key columns are restricted by IS NOT NULL
static const char* good_is_not_null_in_views_query =
"CREATE MATERIALIZED VIEW t_view AS SELECT p, c, a, b FROM t "
"WHERE p IS NOT NULL and c IS NOT NULL and a IS NOT NULL PRIMARY KEY (a, c, p)";
// Bad - b IS NOT NULL is an invalid restriction, as b isn't a part of the view's primary key
sstring bad_is_not_null_in_views_query(int bad_view_index = 0) {
return fmt::format(
"CREATE MATERIALIZED VIEW t_badview_{} AS SELECT p, c, a, b FROM t "
"WHERE p IS NOT NULL and c IS NOT NULL and a IS NOT NULL AND b IS NOT NULL PRIMARY KEY (a, c, p)",
bad_view_index);
}
static bool contains_is_not_null_warning(const cql_transport::messages::result_message& result_msg) {
const std::vector<sstring>& warnings = result_msg.warnings();
auto found_warning = std::find_if(warnings.begin(), warnings.end(), [&](const sstring& warning) -> bool {
return warning.find("IS NOT NULL") != std::string::npos;
});
return found_warning != warnings.end();
}
// Test that setting strict_is_not_null_in_views=true doesn't allow invalid IS NOT NULL in views.
SEASTAR_THREAD_TEST_CASE(strict_is_not_null_in_views_true) {
auto cfg = make_shared<db::config>();
cfg->strict_is_not_null_in_views(db::tri_mode_restriction_t::mode::TRUE);
do_with_cql_env_thread([&](cql_test_env& e) {
cquery_nofail(e, "CREATE TABLE t (p int, c int, a int, b int, PRIMARY KEY (p, c))");
cquery_nofail(e, good_is_not_null_in_views_query);
BOOST_REQUIRE_EXCEPTION(e.execute_cql(bad_is_not_null_in_views_query()).get(),
exceptions::invalid_request_exception,
exception_predicate::message_contains("IS NOT NULL"));
}, cfg).get();
}
// Test that setting strict_is_not_null_in_views=warn allows invalid IS NOT NULL in views, but throws a warning.
SEASTAR_THREAD_TEST_CASE(strict_is_not_null_in_views_warn) {
auto cfg = make_shared<db::config>();
cfg->strict_is_not_null_in_views(db::tri_mode_restriction_t::mode::WARN);
do_with_cql_env_thread([&](cql_test_env& e) {
cquery_nofail(e, "CREATE TABLE t (p int, c int, a int, b int, PRIMARY KEY (p, c))");
cquery_nofail(e, good_is_not_null_in_views_query);
shared_ptr<cql_transport::messages::result_message> bad_res =
e.execute_cql(bad_is_not_null_in_views_query()).get();
BOOST_REQUIRE(contains_is_not_null_warning(*bad_res));
}, cfg).get();
}
// Test that setting strict_is_not_null_in_views=false allows invalid IS NOT NULL in views without any warnings.
SEASTAR_THREAD_TEST_CASE(strict_is_not_null_in_views_false) {
auto cfg = make_shared<db::config>();
cfg->strict_is_not_null_in_views(db::tri_mode_restriction_t::mode::FALSE);
do_with_cql_env_thread([&](cql_test_env& e) {
cquery_nofail(e, "CREATE TABLE t (p int, c int, a int, b int, PRIMARY KEY (p, c))");
cquery_nofail(e, good_is_not_null_in_views_query);
shared_ptr<cql_transport::messages::result_message> bad_res =
e.execute_cql(bad_is_not_null_in_views_query()).get();
BOOST_REQUIRE(!contains_is_not_null_warning(*bad_res));
}, cfg).get();
}
// Test that the strict_is_not_null_in_views flag handles live updates properly.
SEASTAR_THREAD_TEST_CASE(strict_is_not_null_in_views_live_update) {
auto cfg = make_shared<db::config>();
cfg->strict_is_not_null_in_views(db::tri_mode_restriction_t::mode::FALSE);
do_with_cql_env_thread([&](cql_test_env& e) {
cquery_nofail(e, "CREATE TABLE t (p int, c int, a int, b int, PRIMARY KEY (p, c))");
cquery_nofail(e, good_is_not_null_in_views_query);
shared_ptr<cql_transport::messages::result_message> bad_res_with_false =
e.execute_cql(bad_is_not_null_in_views_query(0)).get();
BOOST_REQUIRE(!contains_is_not_null_warning(*bad_res_with_false));
cfg->strict_is_not_null_in_views(db::tri_mode_restriction_t::mode::WARN);
shared_ptr<cql_transport::messages::result_message> bad_res_with_warn =
e.execute_cql(bad_is_not_null_in_views_query(1)).get();
BOOST_REQUIRE(contains_is_not_null_warning(*bad_res_with_warn));
cfg->strict_is_not_null_in_views(db::tri_mode_restriction_t::mode::TRUE);
BOOST_REQUIRE_EXCEPTION(e.execute_cql(bad_is_not_null_in_views_query(2)).get(),
exceptions::invalid_request_exception,
exception_predicate::message_contains("IS NOT NULL"));
}, cfg).get();
}
// Test that the default value for the strict_is_not_null_in_views flag is `warn`.
SEASTAR_THREAD_TEST_CASE(strict_is_not_null_in_views_default_value) {
auto cfg = make_shared<db::config>();
BOOST_REQUIRE(cfg->strict_is_not_null_in_views() == db::tri_mode_restriction_t::mode::WARN);
}
BOOST_AUTO_TEST_SUITE_END()