3791 lines
198 KiB
C++
3791 lines
198 KiB
C++
/*
|
|
* Copyright (C) 2015 ScyllaDB
|
|
*/
|
|
|
|
/*
|
|
* This file is part of Scylla.
|
|
*
|
|
* Scylla is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU Affero General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* Scylla is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with Scylla. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
|
|
#include <boost/range/irange.hpp>
|
|
#include <boost/range/adaptors.hpp>
|
|
#include <boost/range/algorithm.hpp>
|
|
#include <boost/test/unit_test.hpp>
|
|
#include <boost/multiprecision/cpp_int.hpp>
|
|
|
|
#include <seastar/net/inet_address.hh>
|
|
|
|
#include "tests/test-utils.hh"
|
|
#include "tests/cql_test_env.hh"
|
|
#include "tests/cql_assertions.hh"
|
|
|
|
#include "core/future-util.hh"
|
|
#include "core/sleep.hh"
|
|
#include "transport/messages/result_message.hh"
|
|
#include "utils/big_decimal.hh"
|
|
|
|
using namespace std::literals::chrono_literals;
|
|
|
|
SEASTAR_TEST_CASE(test_create_keyspace_statement) {
|
|
return do_with_cql_env([] (cql_test_env& e) {
|
|
return e.execute_cql("create keyspace ks2 with replication = { 'class' : 'SimpleStrategy', 'replication_factor' : 1 };").discard_result().then([&e] {
|
|
return e.require_keyspace_exists("ks2");
|
|
});
|
|
});
|
|
}
|
|
|
|
SEASTAR_TEST_CASE(test_create_table_statement) {
|
|
return do_with_cql_env([] (cql_test_env& e) {
|
|
return e.execute_cql("create table users (user_name varchar PRIMARY KEY, birth_year bigint);").discard_result().then([&e] {
|
|
return e.require_table_exists("ks", "users");
|
|
}).then([&e] {
|
|
return e.execute_cql("create table cf (id int primary key, m map<int, int>, s set<text>, l list<uuid>);").discard_result();
|
|
}).then([&e] {
|
|
return e.require_table_exists("ks", "cf");
|
|
});
|
|
});
|
|
}
|
|
|
|
SEASTAR_TEST_CASE(test_create_table_with_id_statement) {
|
|
return do_with_cql_env([](cql_test_env& e) {
|
|
return seastar::async([&e] {
|
|
e.execute_cql("CREATE TABLE tbl (a int, b int, PRIMARY KEY (a))").get();
|
|
auto id = e.local_db().find_schema("ks", "tbl")->id();
|
|
e.execute_cql("DROP TABLE tbl").get();
|
|
BOOST_REQUIRE_THROW(e.execute_cql("SELECT * FROM tbl").get(), std::exception);
|
|
e.execute_cql(
|
|
format("CREATE TABLE tbl (a int, b int, PRIMARY KEY (a)) WITH id='{}'", id)).get();
|
|
assert_that(e.execute_cql("SELECT * FROM tbl").get0())
|
|
.is_rows().with_size(0);
|
|
BOOST_REQUIRE_THROW(
|
|
e.execute_cql(format("CREATE TABLE tbl2 (a int, b int, PRIMARY KEY (a)) WITH id='{}'", id)).get(),
|
|
exceptions::invalid_request_exception);
|
|
BOOST_REQUIRE_THROW(
|
|
e.execute_cql("CREATE TABLE tbl2 (a int, b int, PRIMARY KEY (a)) WITH id='55'").get(),
|
|
exceptions::configuration_exception);
|
|
BOOST_REQUIRE_THROW(
|
|
e.execute_cql("ALTER TABLE tbl WITH id='f2a8c099-e723-48cb-8cd9-53e647a011a3'").get(),
|
|
exceptions::configuration_exception);
|
|
});
|
|
});
|
|
}
|
|
|
|
SEASTAR_TEST_CASE(test_drop_table_with_si_and_mv) {
|
|
return do_with_cql_env([](cql_test_env& e) {
|
|
return seastar::async([&e] {
|
|
e.execute_cql("CREATE TABLE tbl (a int, b int, c float, PRIMARY KEY (a))").get();
|
|
e.execute_cql("CREATE INDEX idx1 ON tbl (b)").get();
|
|
e.execute_cql("CREATE INDEX idx2 ON tbl (c)").get();
|
|
e.execute_cql("CREATE MATERIALIZED VIEW tbl_view AS SELECT c FROM tbl WHERE c IS NOT NULL PRIMARY KEY (c, a)").get();
|
|
// dropping a table with materialized views is prohibited
|
|
assert_that_failed(e.execute_cql("DROP TABLE tbl"));
|
|
e.execute_cql("DROP MATERIALIZED VIEW tbl_view").get();
|
|
// dropping a table with secondary indexes is fine
|
|
e.execute_cql("DROP TABLE tbl").get();
|
|
|
|
e.execute_cql("CREATE TABLE tbl (a int, b int, c float, PRIMARY KEY (a))").get();
|
|
e.execute_cql("CREATE INDEX idx1 ON tbl (b)").get();
|
|
e.execute_cql("CREATE INDEX idx2 ON tbl (c)").get();
|
|
e.execute_cql("CREATE MATERIALIZED VIEW tbl_view AS SELECT c FROM tbl WHERE c IS NOT NULL PRIMARY KEY (c, a)").get();
|
|
// dropping whole keyspace with MV and SI is fine too
|
|
e.execute_cql("DROP KEYSPACE ks").get();
|
|
});
|
|
});
|
|
}
|
|
|
|
SEASTAR_TEST_CASE(test_insert_statement) {
|
|
return do_with_cql_env([] (cql_test_env& e) {
|
|
return e.execute_cql("create table cf (p1 varchar, c1 int, r1 int, PRIMARY KEY (p1, c1));").discard_result().then([&e] {
|
|
return e.execute_cql("insert into cf (p1, c1, r1) values ('key1', 1, 100);").discard_result();
|
|
}).then([&e] {
|
|
return e.require_column_has_value("cf", {sstring("key1")}, {1}, "r1", 100);
|
|
}).then([&e] {
|
|
return e.execute_cql("update cf set r1 = 66 where p1 = 'key1' and c1 = 1;").discard_result();
|
|
}).then([&e] {
|
|
return e.require_column_has_value("cf", {sstring("key1")}, {1}, "r1", 66);
|
|
});
|
|
});
|
|
}
|
|
|
|
SEASTAR_TEST_CASE(test_select_statement) {
|
|
return do_with_cql_env([] (cql_test_env& e) {
|
|
return e.create_table([](sstring ks_name) {
|
|
// CQL: create table cf (p1 varchar, c1 int, c2 int, r1 int, PRIMARY KEY (p1, c1, c2));
|
|
return schema({}, ks_name, "cf",
|
|
{{"p1", utf8_type}},
|
|
{{"c1", int32_type}, {"c2", int32_type}},
|
|
{{"r1", int32_type}},
|
|
{},
|
|
utf8_type);
|
|
}).then([&e] {
|
|
return e.execute_cql("insert into cf (p1, c1, c2, r1) values ('key1', 1, 2, 3);").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("insert into cf (p1, c1, c2, r1) values ('key2', 1, 2, 13);").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("insert into cf (p1, c1, c2, r1) values ('key3', 1, 2, 23);").discard_result();
|
|
}).then([&e] {
|
|
// Test wildcard
|
|
return e.execute_cql("select * from cf where p1 = 'key1' and c2 = 2 and c1 = 1;").then([] (shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows()
|
|
.with_size(1)
|
|
.with_row({
|
|
{utf8_type->decompose(sstring("key1"))},
|
|
{int32_type->decompose(1)},
|
|
{int32_type->decompose(2)},
|
|
{int32_type->decompose(3)}
|
|
});
|
|
});
|
|
}).then([&e] {
|
|
// Test with only regular column
|
|
return e.execute_cql("select r1 from cf where p1 = 'key1' and c2 = 2 and c1 = 1;").then([] (shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows()
|
|
.with_size(1)
|
|
.with_row({
|
|
{int32_type->decompose(3)}
|
|
});
|
|
});
|
|
}).then([&e] {
|
|
// Test full partition range, singular clustering range
|
|
return e.execute_cql("select * from cf where c1 = 1 and c2 = 2 allow filtering;").then([] (shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows()
|
|
.with_size(3)
|
|
.with_row({
|
|
{utf8_type->decompose(sstring("key1"))},
|
|
{int32_type->decompose(1)},
|
|
{int32_type->decompose(2)},
|
|
{int32_type->decompose(3)}})
|
|
.with_row({
|
|
{utf8_type->decompose(sstring("key2"))},
|
|
{int32_type->decompose(1)},
|
|
{int32_type->decompose(2)},
|
|
{int32_type->decompose(13)}})
|
|
.with_row({
|
|
{utf8_type->decompose(sstring("key3"))},
|
|
{int32_type->decompose(1)},
|
|
{int32_type->decompose(2)},
|
|
{int32_type->decompose(23)}
|
|
});
|
|
});
|
|
});
|
|
});
|
|
}
|
|
|
|
SEASTAR_TEST_CASE(test_cassandra_stress_like_write_and_read) {
|
|
return do_with_cql_env([] (cql_test_env& e) {
|
|
auto execute_update_for_key = [&e](sstring key) {
|
|
return e.execute_cql(sprint("UPDATE cf SET "
|
|
"\"C0\" = 0x8f75da6b3dcec90c8a404fb9a5f6b0621e62d39c69ba5758e5f41b78311fbb26cc7a,"
|
|
"\"C1\" = 0xa8761a2127160003033a8f4f3d1069b7833ebe24ef56b3beee728c2b686ca516fa51,"
|
|
"\"C2\" = 0x583449ce81bfebc2e1a695eb59aad5fcc74d6d7311fc6197b10693e1a161ca2e1c64,"
|
|
"\"C3\" = 0x62bcb1dbc0ff953abc703bcb63ea954f437064c0c45366799658bd6b91d0f92908d7,"
|
|
"\"C4\" = 0x222fcbe31ffa1e689540e1499b87fa3f9c781065fccd10e4772b4c7039c2efd0fb27 "
|
|
"WHERE \"KEY\"=%s;", key)).discard_result();
|
|
};
|
|
|
|
auto verify_row_for_key = [&e](sstring key) {
|
|
return e.execute_cql(
|
|
format("select \"C0\", \"C1\", \"C2\", \"C3\", \"C4\" from cf where \"KEY\" = {}", key)).then(
|
|
[](shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows()
|
|
.with_size(1)
|
|
.with_row({
|
|
{from_hex(
|
|
"8f75da6b3dcec90c8a404fb9a5f6b0621e62d39c69ba5758e5f41b78311fbb26cc7a")},
|
|
{from_hex(
|
|
"a8761a2127160003033a8f4f3d1069b7833ebe24ef56b3beee728c2b686ca516fa51")},
|
|
{from_hex(
|
|
"583449ce81bfebc2e1a695eb59aad5fcc74d6d7311fc6197b10693e1a161ca2e1c64")},
|
|
{from_hex(
|
|
"62bcb1dbc0ff953abc703bcb63ea954f437064c0c45366799658bd6b91d0f92908d7")},
|
|
{from_hex("222fcbe31ffa1e689540e1499b87fa3f9c781065fccd10e4772b4c7039c2efd0fb27")}
|
|
});
|
|
});
|
|
};
|
|
|
|
return e.create_table([](sstring ks_name) {
|
|
return schema({}, ks_name, "cf",
|
|
{{"KEY", bytes_type}},
|
|
{},
|
|
{{"C0", bytes_type},
|
|
{"C1", bytes_type},
|
|
{"C2", bytes_type},
|
|
{"C3", bytes_type},
|
|
{"C4", bytes_type}},
|
|
{},
|
|
utf8_type);
|
|
}).then([execute_update_for_key, verify_row_for_key] {
|
|
static auto make_key = [](int suffix) { return format("0xdeadbeefcafebabe{:02d}", suffix); };
|
|
auto suffixes = boost::irange(0, 10);
|
|
return parallel_for_each(suffixes.begin(), suffixes.end(), [execute_update_for_key](int suffix) {
|
|
return execute_update_for_key(make_key(suffix));
|
|
}).then([suffixes, verify_row_for_key] {
|
|
return parallel_for_each(suffixes.begin(), suffixes.end(), [verify_row_for_key](int suffix) {
|
|
return verify_row_for_key(make_key(suffix));
|
|
});
|
|
});
|
|
});
|
|
});
|
|
}
|
|
|
|
SEASTAR_TEST_CASE(test_range_queries) {
|
|
return do_with_cql_env([] (cql_test_env& e) {
|
|
return e.create_table([](sstring ks_name) {
|
|
return schema({}, ks_name, "cf",
|
|
{{"k", bytes_type}},
|
|
{{"c0", bytes_type}, {"c1", bytes_type}},
|
|
{{"v", bytes_type}},
|
|
{},
|
|
utf8_type);
|
|
}).then([&e] {
|
|
return e.execute_cql("update cf set v = 0x01 where k = 0x00 and c0 = 0x01 and c1 = 0x01;").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("update cf set v = 0x02 where k = 0x00 and c0 = 0x01 and c1 = 0x02;").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("update cf set v = 0x03 where k = 0x00 and c0 = 0x01 and c1 = 0x03;").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("update cf set v = 0x04 where k = 0x00 and c0 = 0x02 and c1 = 0x02;").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("update cf set v = 0x05 where k = 0x00 and c0 = 0x02 and c1 = 0x03;").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("update cf set v = 0x06 where k = 0x00 and c0 = 0x02 and c1 = 0x04;").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("update cf set v = 0x07 where k = 0x00 and c0 = 0x03 and c1 = 0x04;").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("update cf set v = 0x08 where k = 0x00 and c0 = 0x03 and c1 = 0x05;").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("select v from cf where k = 0x00").then([] (shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows()
|
|
.with_rows({
|
|
{from_hex("01")},
|
|
{from_hex("02")},
|
|
{from_hex("03")},
|
|
{from_hex("04")},
|
|
{from_hex("05")},
|
|
{from_hex("06")},
|
|
{from_hex("07")},
|
|
{from_hex("08")}
|
|
});
|
|
});
|
|
}).then([&e] {
|
|
return e.execute_cql("select v from cf where k = 0x00 and c0 = 0x02 allow filtering;").then([] (shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().with_rows({
|
|
{from_hex("04")}, {from_hex("05")}, {from_hex("06")}
|
|
});
|
|
});
|
|
}).then([&e] {
|
|
return e.execute_cql("select v from cf where k = 0x00 and c0 > 0x02 allow filtering;").then([] (shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().with_rows({
|
|
{from_hex("07")}, {from_hex("08")}
|
|
});
|
|
});
|
|
}).then([&e] {
|
|
return e.execute_cql("select v from cf where k = 0x00 and c0 >= 0x02 allow filtering;").then([] (shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().with_rows({
|
|
{from_hex("04")}, {from_hex("05")}, {from_hex("06")}, {from_hex("07")}, {from_hex("08")}
|
|
});
|
|
});
|
|
}).then([&e] {
|
|
return e.execute_cql("select v from cf where k = 0x00 and c0 >= 0x02 and c0 < 0x03 allow filtering;").then([] (shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().with_rows({
|
|
{from_hex("04")}, {from_hex("05")}, {from_hex("06")}
|
|
});
|
|
});
|
|
}).then([&e] {
|
|
return e.execute_cql("select v from cf where k = 0x00 and c0 > 0x02 and c0 <= 0x03 allow filtering;").then([] (shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().with_rows({
|
|
{from_hex("07")}, {from_hex("08")}
|
|
});
|
|
});
|
|
}).then([&e] {
|
|
return e.execute_cql("select v from cf where k = 0x00 and c0 >= 0x02 and c0 <= 0x02 allow filtering;").then([] (shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().with_rows({
|
|
{from_hex("04")}, {from_hex("05")}, {from_hex("06")}
|
|
});
|
|
});
|
|
}).then([&e] {
|
|
return e.execute_cql("select v from cf where k = 0x00 and c0 < 0x02 allow filtering;").then([] (shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().with_rows({
|
|
{from_hex("01")}, {from_hex("02")}, {from_hex("03")}
|
|
});
|
|
});
|
|
}).then([&e] {
|
|
return e.execute_cql("select v from cf where k = 0x00 and c0 = 0x02 and c1 > 0x02 allow filtering;").then([] (shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().with_rows({
|
|
{from_hex("05")}, {from_hex("06")}
|
|
});
|
|
});
|
|
}).then([&e] {
|
|
return e.execute_cql("select v from cf where k = 0x00 and c0 = 0x02 and c1 >= 0x02 and c1 <= 0x02 allow filtering;").then([] (shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().with_rows({
|
|
{from_hex("04")}
|
|
});
|
|
});
|
|
});
|
|
});
|
|
}
|
|
|
|
SEASTAR_TEST_CASE(test_ordering_of_composites_with_variable_length_components) {
|
|
return do_with_cql_env([] (cql_test_env& e) {
|
|
return e.create_table([](sstring ks) {
|
|
return schema({}, ks, "cf",
|
|
{{"k", bytes_type}},
|
|
// We need more than one clustering column so that the single-element tuple format optimisation doesn't kick in
|
|
{{"c0", bytes_type}, {"c1", bytes_type}},
|
|
{{"v", bytes_type}},
|
|
{},
|
|
utf8_type);
|
|
}).then([&e] {
|
|
return e.execute_cql("update cf set v = 0x01 where k = 0x00 and c0 = 0x0001 and c1 = 0x00;").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("update cf set v = 0x02 where k = 0x00 and c0 = 0x03 and c1 = 0x00;").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("update cf set v = 0x03 where k = 0x00 and c0 = 0x035555 and c1 = 0x00;").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("update cf set v = 0x04 where k = 0x00 and c0 = 0x05 and c1 = 0x00;").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("select v from cf where k = 0x00 allow filtering;").then([](shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().with_rows({
|
|
{from_hex("01")}, {from_hex("02")}, {from_hex("03")}, {from_hex("04")}
|
|
});
|
|
});
|
|
});
|
|
});
|
|
}
|
|
|
|
SEASTAR_TEST_CASE(test_query_with_static_columns) {
|
|
return do_with_cql_env([] (cql_test_env& e) {
|
|
return e.execute_cql("create table cf (k blob, c blob, v blob, s1 blob static, s2 blob static, primary key (k, c));").discard_result().then([&e] {
|
|
return e.execute_cql("update cf set s1 = 0x01 where k = 0x00;").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("update cf set v = 0x02 where k = 0x00 and c = 0x01;").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("update cf set v = 0x03 where k = 0x00 and c = 0x02;").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("select s1, v from cf;").then([](shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().with_rows({
|
|
{from_hex("01"), from_hex("02")},
|
|
{from_hex("01"), from_hex("03")},
|
|
});
|
|
});
|
|
}).then([&e] {
|
|
return e.execute_cql("select s1 from cf;").then([](shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().with_rows({
|
|
{from_hex("01")},
|
|
{from_hex("01")},
|
|
});
|
|
});
|
|
}).then([&e] {
|
|
return e.execute_cql("select s1 from cf limit 1;").then([](shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().with_rows({
|
|
{from_hex("01")},
|
|
});
|
|
});
|
|
}).then([&e] {
|
|
return e.execute_cql("select s1, v from cf limit 1;").then([](shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().with_rows({
|
|
{from_hex("01"), from_hex("02")},
|
|
});
|
|
});
|
|
}).then([&e] {
|
|
return e.execute_cql("update cf set v = null where k = 0x00 and c = 0x02;").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("select s1 from cf;").then([](shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().with_rows({
|
|
{from_hex("01")},
|
|
});
|
|
});
|
|
}).then([&e] {
|
|
return e.execute_cql("insert into cf (k, c) values (0x00, 0x02);").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("select s1 from cf;").then([](shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().with_rows({
|
|
{from_hex("01")},
|
|
{from_hex("01")},
|
|
});
|
|
});
|
|
}).then([&e] {
|
|
// Try 'in' restriction out
|
|
return e.execute_cql("select s1, v from cf where k = 0x00 and c in (0x01, 0x02);").then([](shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().with_rows({
|
|
{from_hex("01"), from_hex("02")},
|
|
{from_hex("01"), {}}
|
|
});
|
|
});
|
|
}).then([&e] {
|
|
// Verify that limit is respected for multiple clustering ranges and that static columns
|
|
// are populated when limit kicks in.
|
|
return e.execute_cql("select s1, v from cf where k = 0x00 and c in (0x01, 0x02) limit 1;").then([](shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().with_rows({
|
|
{from_hex("01"), from_hex("02")}
|
|
});
|
|
});
|
|
});
|
|
});
|
|
}
|
|
|
|
SEASTAR_TEST_CASE(test_insert_without_clustering_key) {
|
|
return do_with_cql_env([] (cql_test_env& e) {
|
|
return e.execute_cql("create table cf (k blob, v blob, primary key (k));").discard_result().then([&e] {
|
|
return e.execute_cql("insert into cf (k) values (0x01);").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("select * from cf;").then([](shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().with_rows({
|
|
{from_hex("01"), {}}
|
|
});
|
|
});
|
|
}).then([&e] {
|
|
return e.execute_cql("select k from cf;").then([](shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().with_rows({
|
|
{from_hex("01")}
|
|
});
|
|
});
|
|
});
|
|
});
|
|
}
|
|
|
|
SEASTAR_TEST_CASE(test_limit_is_respected_across_partitions) {
|
|
return do_with_cql_env([] (cql_test_env& e) {
|
|
return e.execute_cql("create table cf (k blob, c blob, v blob, s1 blob static, primary key (k, c));").discard_result().then([&e] {
|
|
return e.execute_cql("update cf set s1 = 0x01 where k = 0x01;").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("update cf set s1 = 0x02 where k = 0x02;").discard_result();
|
|
}).then([&e] {
|
|
// Determine partition order
|
|
return e.execute_cql("select k from cf;");
|
|
}).then([&e](shared_ptr<cql_transport::messages::result_message> msg) {
|
|
auto rows = dynamic_pointer_cast<cql_transport::messages::result_message::rows>(msg);
|
|
BOOST_REQUIRE(rows);
|
|
std::vector<bytes> keys;
|
|
auto rs = rows->rs().result_set();
|
|
for (auto&& row : rs.rows()) {
|
|
BOOST_REQUIRE(row[0]);
|
|
keys.push_back(*row[0]);
|
|
}
|
|
BOOST_REQUIRE(keys.size() == 2);
|
|
bytes k1 = keys[0];
|
|
bytes k2 = keys[1];
|
|
|
|
return now().then([k1, k2, &e] {
|
|
return e.execute_cql("select s1 from cf limit 1;").then([k1, k2](shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().with_rows({
|
|
{k1},
|
|
});
|
|
});
|
|
}).then([&e, k1, k2] {
|
|
return e.execute_cql("select s1 from cf limit 2;").then([k1, k2](shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().with_rows({
|
|
{k1}, {k2}
|
|
});
|
|
});
|
|
}).then([&e, k1, k2] {
|
|
return e.execute_cql(format("update cf set s1 = null where k = 0x{};", to_hex(k1))).discard_result();
|
|
}).then([&e, k1, k2] {
|
|
return e.execute_cql("select s1 from cf limit 1;").then([k1, k2](shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().with_rows({
|
|
{k2}
|
|
});
|
|
});
|
|
}).then([&e, k1, k2] {
|
|
return e.execute_cql(format("update cf set s1 = null where k = 0x{};", to_hex(k2))).discard_result();
|
|
}).then([&e, k1, k2] {
|
|
return e.execute_cql("select s1 from cf limit 1;").then([k1, k2](shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().is_empty();
|
|
});
|
|
});
|
|
});
|
|
});
|
|
}
|
|
|
|
SEASTAR_TEST_CASE(test_partitions_have_consistent_ordering_in_range_query) {
|
|
return do_with_cql_env([] (cql_test_env& e) {
|
|
return e.execute_cql("create table cf (k blob, v int, primary key (k));").discard_result().then([&e] {
|
|
return e.execute_cql(
|
|
"begin unlogged batch \n"
|
|
" insert into cf (k, v) values (0x01, 0); \n"
|
|
" insert into cf (k, v) values (0x02, 0); \n"
|
|
" insert into cf (k, v) values (0x03, 0); \n"
|
|
" insert into cf (k, v) values (0x04, 0); \n"
|
|
" insert into cf (k, v) values (0x05, 0); \n"
|
|
" insert into cf (k, v) values (0x06, 0); \n"
|
|
"apply batch;"
|
|
).discard_result();
|
|
}).then([&e] {
|
|
// Determine partition order
|
|
return e.execute_cql("select k from cf;");
|
|
}).then([&e](shared_ptr<cql_transport::messages::result_message> msg) {
|
|
auto rows = dynamic_pointer_cast<cql_transport::messages::result_message::rows>(msg);
|
|
BOOST_REQUIRE(rows);
|
|
std::vector<bytes> keys;
|
|
auto rs = rows->rs().result_set();
|
|
for (auto&& row : rs.rows()) {
|
|
BOOST_REQUIRE(row[0]);
|
|
keys.push_back(*row[0]);
|
|
}
|
|
BOOST_REQUIRE(keys.size() == 6);
|
|
|
|
return now().then([keys, &e] {
|
|
return e.execute_cql("select k from cf limit 1;").then([keys](shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().with_rows({
|
|
{keys[0]}
|
|
});
|
|
});
|
|
}).then([keys, &e] {
|
|
return e.execute_cql("select k from cf limit 2;").then([keys](shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().with_rows({
|
|
{keys[0]},
|
|
{keys[1]}
|
|
});
|
|
});
|
|
}).then([keys, &e] {
|
|
return e.execute_cql("select k from cf limit 3;").then([keys](shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().with_rows({
|
|
{keys[0]},
|
|
{keys[1]},
|
|
{keys[2]}
|
|
});
|
|
});
|
|
}).then([keys, &e] {
|
|
return e.execute_cql("select k from cf limit 4;").then([keys](shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().with_rows({
|
|
{keys[0]},
|
|
{keys[1]},
|
|
{keys[2]},
|
|
{keys[3]}
|
|
});
|
|
});
|
|
}).then([keys, &e] {
|
|
return e.execute_cql("select k from cf limit 5;").then([keys](shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().with_rows({
|
|
{keys[0]},
|
|
{keys[1]},
|
|
{keys[2]},
|
|
{keys[3]},
|
|
{keys[4]}
|
|
});
|
|
});
|
|
}).then([keys, &e] {
|
|
return e.execute_cql("select k from cf limit 6;").then([keys](shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().with_rows({
|
|
{keys[0]},
|
|
{keys[1]},
|
|
{keys[2]},
|
|
{keys[3]},
|
|
{keys[4]},
|
|
{keys[5]}
|
|
});
|
|
});
|
|
});
|
|
});
|
|
});
|
|
}
|
|
|
|
SEASTAR_TEST_CASE(test_partition_range_queries_with_bounds) {
|
|
return do_with_cql_env([] (cql_test_env& e) {
|
|
return e.execute_cql("create table cf (k blob, v int, primary key (k));").discard_result().then([&e] {
|
|
return e.execute_cql(
|
|
"begin unlogged batch \n"
|
|
" insert into cf (k, v) values (0x01, 0); \n"
|
|
" insert into cf (k, v) values (0x02, 0); \n"
|
|
" insert into cf (k, v) values (0x03, 0); \n"
|
|
" insert into cf (k, v) values (0x04, 0); \n"
|
|
" insert into cf (k, v) values (0x05, 0); \n"
|
|
"apply batch;"
|
|
).discard_result();
|
|
}).then([&e] {
|
|
// Determine partition order
|
|
return e.execute_cql("select k, token(k) from cf;");
|
|
}).then([&e](shared_ptr<cql_transport::messages::result_message> msg) {
|
|
auto rows = dynamic_pointer_cast<cql_transport::messages::result_message::rows>(msg);
|
|
BOOST_REQUIRE(rows);
|
|
std::vector<bytes> keys;
|
|
std::vector<int64_t> tokens;
|
|
auto rs = rows->rs().result_set();
|
|
for (auto&& row : rs.rows()) {
|
|
BOOST_REQUIRE(row[0]);
|
|
BOOST_REQUIRE(row[1]);
|
|
keys.push_back(*row[0]);
|
|
tokens.push_back(value_cast<int64_t>(long_type->deserialize(*row[1])));
|
|
}
|
|
BOOST_REQUIRE(keys.size() == 5);
|
|
|
|
return now().then([keys, tokens, &e] {
|
|
return e.execute_cql(format("select k from cf where token(k) > {:d};", tokens[1])).then([keys](shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().with_rows({
|
|
{keys[2]},
|
|
{keys[3]},
|
|
{keys[4]}
|
|
});
|
|
});
|
|
}).then([keys, tokens, &e] {
|
|
return e.execute_cql(format("select k from cf where token(k) >= {:d};", tokens[1])).then([keys](shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().with_rows({
|
|
{keys[1]},
|
|
{keys[2]},
|
|
{keys[3]},
|
|
{keys[4]}
|
|
});
|
|
});
|
|
}).then([keys, tokens, &e] {
|
|
return e.execute_cql(format("select k from cf where token(k) > {:d} and token(k) < {:d};",
|
|
tokens[1], tokens[4])).then([keys](shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().with_rows({
|
|
{keys[2]},
|
|
{keys[3]},
|
|
});
|
|
});
|
|
}).then([keys, tokens, &e] {
|
|
return e.execute_cql(format("select k from cf where token(k) < {:d};", tokens[3])).then([keys](shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().with_rows({
|
|
{keys[0]},
|
|
{keys[1]},
|
|
{keys[2]}
|
|
});
|
|
});
|
|
}).then([keys, tokens, &e] {
|
|
return e.execute_cql(format("select k from cf where token(k) = {:d};", tokens[3])).then([keys](shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().with_rows({
|
|
{keys[3]}
|
|
});
|
|
});
|
|
}).then([keys, tokens, &e] {
|
|
return e.execute_cql(format("select k from cf where token(k) < {:d} and token(k) > {:d};", tokens[3], tokens[3])).then([keys](shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().is_empty();
|
|
});
|
|
}).then([keys, tokens, &e] {
|
|
return e.execute_cql(format("select k from cf where token(k) >= {:d} and token(k) <= {:d};", tokens[4], tokens[2])).then([keys](shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().is_empty();
|
|
});
|
|
}).then([keys, tokens, &e] {
|
|
auto min_token = std::numeric_limits<int64_t>::min();
|
|
return e.execute_cql(format("select k from cf where token(k) > {:d} and token (k) < {:d};", min_token, min_token)).then([keys](shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().with_rows({
|
|
{keys[0]},
|
|
{keys[1]},
|
|
{keys[2]},
|
|
{keys[3]},
|
|
{keys[4]}
|
|
});
|
|
});
|
|
});
|
|
});
|
|
});
|
|
}
|
|
|
|
SEASTAR_TEST_CASE(test_deletion_scenarios) {
|
|
return do_with_cql_env([] (cql_test_env& e) {
|
|
return e.create_table([](sstring ks) {
|
|
// CQL: create table cf (k bytes, c bytes, v bytes, primary key (k, c));
|
|
return schema({}, ks, "cf",
|
|
{{"k", bytes_type}}, {{"c", bytes_type}}, {{"v", bytes_type}}, {}, utf8_type);
|
|
}).then([&e] {
|
|
return e.execute_cql("insert into cf (k, c, v) values (0x00, 0x05, 0x01) using timestamp 1;").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("select v from cf;").then([](shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().with_rows({
|
|
{from_hex("01")},
|
|
});
|
|
});
|
|
}).then([&e] {
|
|
return e.execute_cql("update cf using timestamp 2 set v = null where k = 0x00 and c = 0x05;").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("select v from cf;").then([](shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().with_rows({
|
|
{{}},
|
|
});
|
|
});
|
|
}).then([&e] {
|
|
// same tampstamp, dead cell wins
|
|
return e.execute_cql("update cf using timestamp 2 set v = 0x02 where k = 0x00 and c = 0x05;").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("select v from cf;").then([](shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().with_rows({
|
|
{{}},
|
|
});
|
|
});
|
|
}).then([&e] {
|
|
return e.execute_cql("update cf using timestamp 3 set v = 0x02 where k = 0x00 and c = 0x05;").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("select v from cf;").then([](shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().with_rows({
|
|
{from_hex("02")},
|
|
});
|
|
});
|
|
}).then([&e] {
|
|
// same timestamp, greater value wins
|
|
return e.execute_cql("update cf using timestamp 3 set v = 0x03 where k = 0x00 and c = 0x05;").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("select v from cf;").then([](shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().with_rows({
|
|
{from_hex("03")},
|
|
});
|
|
});
|
|
}).then([&e] {
|
|
// same tampstamp, delete whole row, delete should win
|
|
return e.execute_cql("delete from cf using timestamp 3 where k = 0x00 and c = 0x05;").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("select v from cf;").then([](shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().is_empty();
|
|
});
|
|
}).then([&e] {
|
|
// same timestamp, update should be shadowed by range tombstone
|
|
return e.execute_cql("update cf using timestamp 3 set v = 0x04 where k = 0x00 and c = 0x05;").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("select v from cf;").then([](shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().is_empty();
|
|
});
|
|
}).then([&e] {
|
|
return e.execute_cql("update cf using timestamp 4 set v = 0x04 where k = 0x00 and c = 0x05;").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("select v from cf;").then([](shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().with_rows({
|
|
{from_hex("04")},
|
|
});
|
|
});
|
|
}).then([&e] {
|
|
// deleting an orphan cell (row is considered as deleted) yields no row
|
|
return e.execute_cql("update cf using timestamp 5 set v = null where k = 0x00 and c = 0x05;").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("select v from cf;").then([](shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().is_empty();
|
|
});
|
|
});
|
|
});
|
|
}
|
|
|
|
SEASTAR_TEST_CASE(test_range_deletion_scenarios) {
|
|
return do_with_cql_env_thread([] (cql_test_env& e) {
|
|
e.execute_cql("create table cf (p int, c int, v text, primary key (p, c));").get();
|
|
for (auto i = 0; i < 10; ++i) {
|
|
e.execute_cql(format("insert into cf (p, c, v) values (1, {:d}, 'abc');", i)).get();
|
|
}
|
|
|
|
try {
|
|
e.execute_cql("delete from cf where p = 1 and c <= 3").get();
|
|
BOOST_FAIL("should've thrown");
|
|
} catch (...) { }
|
|
try {
|
|
e.execute_cql("delete from cf where p = 1 and c >= 0").get();
|
|
BOOST_FAIL("should've thrown");
|
|
} catch (...) { }
|
|
|
|
e.execute_cql("delete from cf where p = 1 and c >= 0 and c <= 3").get();
|
|
auto msg = e.execute_cql("select * from cf").get0();
|
|
assert_that(msg).is_rows().with_size(6);
|
|
e.execute_cql("delete from cf where p = 1 and c > 3 and c < 10").get();
|
|
msg = e.execute_cql("select * from cf").get0();
|
|
assert_that(msg).is_rows().with_size(0);
|
|
|
|
e.execute_cql("insert into cf (p, c, v) values (1, 1, '1');").get();
|
|
e.execute_cql("insert into cf (p, c, v) values (1, 3, '3');").get();
|
|
e.execute_cql("delete from cf where p = 1 and c >= 2 and c <= 3").get();
|
|
e.execute_cql("insert into cf (p, c, v) values (1, 2, '2');").get();
|
|
msg = e.execute_cql("select * from cf").get0();
|
|
assert_that(msg).is_rows().with_size(2);
|
|
e.execute_cql("delete from cf where p = 1 and c >= 2 and c <= 3").get();
|
|
msg = e.execute_cql("select * from cf").get0();
|
|
assert_that(msg).is_rows().with_rows({{ {int32_type->decompose(1)}, {int32_type->decompose(1)}, {utf8_type->decompose("1")} }});
|
|
});
|
|
}
|
|
|
|
SEASTAR_TEST_CASE(test_range_deletion_scenarios_with_compact_storage) {
|
|
return do_with_cql_env_thread([] (cql_test_env& e) {
|
|
e.execute_cql("create table cf (p int, c int, v text, primary key (p, c)) with compact storage;").get();
|
|
for (auto i = 0; i < 10; ++i) {
|
|
e.execute_cql(format("insert into cf (p, c, v) values (1, {:d}, 'abc');", i)).get();
|
|
}
|
|
|
|
try {
|
|
e.execute_cql("delete from cf where p = 1 and c <= 3").get();
|
|
BOOST_FAIL("should've thrown");
|
|
} catch (...) { }
|
|
try {
|
|
e.execute_cql("delete from cf where p = 1 and c >= 0").get();
|
|
BOOST_FAIL("should've thrown");
|
|
} catch (...) { }
|
|
try {
|
|
e.execute_cql("delete from cf where p = 1 and c > 0 and c <= 3").get();
|
|
BOOST_FAIL("should've thrown");
|
|
} catch (...) { }
|
|
try {
|
|
e.execute_cql("delete from cf where p = 1 and c >= 0 and c < 3").get();
|
|
BOOST_FAIL("should've thrown");
|
|
} catch (...) { }
|
|
try {
|
|
e.execute_cql("delete from cf where p = 1 and c > 0 and c < 3").get();
|
|
BOOST_FAIL("should've thrown");
|
|
} catch (...) { }
|
|
try {
|
|
e.execute_cql("delete from cf where p = 1 and c >= 0 and c <= 3").get();
|
|
BOOST_FAIL("should've thrown");
|
|
} catch (...) { }
|
|
});
|
|
}
|
|
|
|
SEASTAR_TEST_CASE(test_map_insert_update) {
|
|
return do_with_cql_env([] (cql_test_env& e) {
|
|
auto make_my_map_type = [] { return map_type_impl::get_instance(int32_type, int32_type, true); };
|
|
auto my_map_type = make_my_map_type();
|
|
return e.create_table([make_my_map_type] (sstring ks_name) {
|
|
// CQL: create table cf (p1 varchar primary key, map1 map<int, int>);
|
|
return schema({}, ks_name, "cf",
|
|
{{"p1", utf8_type}}, {}, {{"map1", make_my_map_type()}}, {}, utf8_type);
|
|
}).then([&e] {
|
|
return e.execute_cql("insert into cf (p1, map1) values ('key1', { 1001: 2001 });").discard_result();
|
|
}).then([&e, my_map_type] {
|
|
return e.require_column_has_value("cf", {sstring("key1")}, {},
|
|
"map1", make_map_value(my_map_type, map_type_impl::native_type({{1001, 2001}})));
|
|
}).then([&e] {
|
|
return e.execute_cql("update cf set map1[1002] = 2002 where p1 = 'key1';").discard_result();
|
|
}).then([&e, my_map_type] {
|
|
return e.require_column_has_value("cf", {sstring("key1")}, {},
|
|
"map1", make_map_value(my_map_type,
|
|
map_type_impl::native_type({{1001, 2001},
|
|
{1002, 2002}})));
|
|
}).then([&e] {
|
|
// overwrite an element
|
|
return e.execute_cql("update cf set map1[1001] = 3001 where p1 = 'key1';").discard_result();
|
|
}).then([&e, my_map_type] {
|
|
return e.require_column_has_value("cf", {sstring("key1")}, {},
|
|
"map1", make_map_value(my_map_type,
|
|
map_type_impl::native_type({{1001, 3001},
|
|
{1002, 2002}})));
|
|
}).then([&e] {
|
|
// overwrite whole map
|
|
return e.execute_cql("update cf set map1 = {1003: 4003} where p1 = 'key1';").discard_result();
|
|
}).then([&e, my_map_type] {
|
|
return e.require_column_has_value("cf", {sstring("key1")}, {},
|
|
"map1", make_map_value(my_map_type,
|
|
map_type_impl::native_type({{1003, 4003}})));
|
|
}).then([&e] {
|
|
// overwrite whole map, but bad syntax
|
|
return e.execute_cql("update cf set map1 = {1003, 4003} where p1 = 'key1';");
|
|
}).then_wrapped([](future<shared_ptr<cql_transport::messages::result_message>> f) {
|
|
BOOST_REQUIRE(f.failed());
|
|
std::move(f).discard_result();
|
|
}).then([&e] {
|
|
// overwrite whole map
|
|
return e.execute_cql(
|
|
"update cf set map1 = {1001: 5001, 1002: 5002, 1003: 5003} where p1 = 'key1';").discard_result();
|
|
}).then([&e, my_map_type] {
|
|
return e.require_column_has_value("cf", {sstring("key1")}, {},
|
|
"map1", make_map_value(my_map_type,
|
|
map_type_impl::native_type({{1001, 5001},
|
|
{1002, 5002},
|
|
{1003, 5003}})));
|
|
}).then([&e] {
|
|
// discard some keys
|
|
return e.execute_cql("update cf set map1 = map1 - {1001, 1003, 1005} where p1 = 'key1';").discard_result();
|
|
}).then([&e, my_map_type] {
|
|
return e.require_column_has_value("cf", {sstring("key1")}, {},
|
|
"map1", make_map_value(my_map_type,
|
|
map_type_impl::native_type({{{1002, 5002}}})));
|
|
}).then([&e, my_map_type] {
|
|
return e.execute_cql("select * from cf where p1 = 'key1';").then([my_map_type](shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows()
|
|
.with_size(1)
|
|
.with_row({
|
|
{utf8_type->decompose(sstring("key1"))},
|
|
{my_map_type->decompose(make_map_value(my_map_type, map_type_impl::native_type{{{1002, 5002}}}))},
|
|
});
|
|
});
|
|
}).then([&e] {
|
|
// overwrite an element
|
|
return e.execute_cql("update cf set map1[1009] = 5009 where p1 = 'key1';").discard_result();
|
|
}).then([&e] {
|
|
// delete a key
|
|
return e.execute_cql("delete map1[1002] from cf where p1 = 'key1';").discard_result();
|
|
}).then([&e, my_map_type] {
|
|
return e.require_column_has_value("cf", {sstring("key1")}, {},
|
|
"map1", make_map_value(my_map_type,
|
|
map_type_impl::native_type({{{1009, 5009}}})));
|
|
}).then([&e] {
|
|
return e.execute_cql("insert into cf (p1, map1) values ('key1', null);").discard_result();
|
|
}).then([&e, my_map_type] {
|
|
return e.require_column_has_value("cf", {sstring("key1")}, {},
|
|
"map1", make_map_value(my_map_type, map_type_impl::native_type({})));
|
|
});
|
|
});
|
|
}
|
|
|
|
SEASTAR_TEST_CASE(test_set_insert_update) {
|
|
return do_with_cql_env([] (cql_test_env& e) {
|
|
auto make_my_set_type = [] { return set_type_impl::get_instance(int32_type, true); };
|
|
auto my_set_type = make_my_set_type();
|
|
return e.create_table([make_my_set_type](sstring ks_name) {
|
|
// CQL: create table cf (p1 varchar primary key, set1 set<int>);
|
|
return schema({}, ks_name, "cf",
|
|
{{"p1", utf8_type}}, {}, {{"set1", make_my_set_type()}}, {}, utf8_type);
|
|
}).then([&e] {
|
|
return e.execute_cql("insert into cf (p1, set1) values ('key1', { 1001 });").discard_result();
|
|
}).then([&e, my_set_type] {
|
|
return e.require_column_has_value("cf", {sstring("key1")}, {},
|
|
"set1", make_set_value(my_set_type, set_type_impl::native_type({{1001}})));
|
|
}).then([&e] {
|
|
return e.execute_cql("update cf set set1 = set1 + { 1002 } where p1 = 'key1';").discard_result();
|
|
}).then([&e, my_set_type] {
|
|
return e.require_column_has_value("cf", {sstring("key1")}, {},
|
|
"set1", make_set_value(my_set_type, set_type_impl::native_type({1001, 1002})));
|
|
}).then([&e] {
|
|
// overwrite an element
|
|
return e.execute_cql("update cf set set1 = set1 + { 1001 } where p1 = 'key1';").discard_result();
|
|
}).then([&e, my_set_type] {
|
|
return e.require_column_has_value("cf", {sstring("key1")}, {},
|
|
"set1", make_set_value(my_set_type, set_type_impl::native_type({1001, 1002})));
|
|
}).then([&e] {
|
|
// overwrite entire set
|
|
return e.execute_cql("update cf set set1 = { 1007, 1019 } where p1 = 'key1';").discard_result();
|
|
}).then([&e, my_set_type] {
|
|
return e.require_column_has_value("cf", {sstring("key1")}, {},
|
|
"set1", make_set_value(my_set_type, set_type_impl::native_type({1007, 1019})));
|
|
}).then([&e] {
|
|
// discard keys
|
|
return e.execute_cql("update cf set set1 = set1 - { 1007, 1008 } where p1 = 'key1';").discard_result();
|
|
}).then([&e, my_set_type] {
|
|
return e.require_column_has_value("cf", {sstring("key1")}, {},
|
|
"set1", make_set_value(my_set_type, set_type_impl::native_type({{1019}})));
|
|
}).then([&e, my_set_type] {
|
|
return e.execute_cql("select * from cf where p1 = 'key1';").then([my_set_type](shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows()
|
|
.with_size(1)
|
|
.with_row({
|
|
{utf8_type->decompose(sstring("key1"))},
|
|
{my_set_type->decompose(make_set_value(my_set_type, set_type_impl::native_type{{1019}}))},
|
|
});
|
|
});
|
|
}).then([&e] {
|
|
return e.execute_cql("update cf set set1 = set1 + { 1009 } where p1 = 'key1';").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("delete set1[1019] from cf where p1 = 'key1';").discard_result();
|
|
}).then([&e, my_set_type] {
|
|
return e.require_column_has_value("cf", {sstring("key1")}, {},
|
|
"set1", make_set_value(my_set_type, set_type_impl::native_type({{1009}})));
|
|
}).then([&e] {
|
|
return e.execute_cql("insert into cf (p1, set1) values ('key1', null);").discard_result();
|
|
}).then([&e, my_set_type] {
|
|
return e.require_column_has_value("cf", {sstring("key1")}, {},
|
|
"set1", make_set_value(my_set_type, set_type_impl::native_type({})));
|
|
});
|
|
});
|
|
}
|
|
|
|
SEASTAR_TEST_CASE(test_list_insert_update) {
|
|
return do_with_cql_env([] (cql_test_env& e) {
|
|
auto my_list_type = list_type_impl::get_instance(int32_type, true);
|
|
return e.execute_cql("create table cf (p1 varchar primary key, list1 list<int>);").discard_result().then([&e] {
|
|
return e.execute_cql("insert into cf (p1, list1) values ('key1', [ 1001 ]);").discard_result();
|
|
}).then([&e, my_list_type] {
|
|
return e.require_column_has_value("cf", {sstring("key1")}, {},
|
|
"list1", make_list_value(my_list_type, list_type_impl::native_type({{1001}})));
|
|
}).then([&e] {
|
|
return e.execute_cql("update cf set list1 = [ 1002, 1003 ] where p1 = 'key1';").discard_result();
|
|
}).then([&e, my_list_type] {
|
|
return e.require_column_has_value("cf", {sstring("key1")}, {},
|
|
"list1", make_list_value(my_list_type, list_type_impl::native_type({1002, 1003})));
|
|
}).then([&e] {
|
|
return e.execute_cql("update cf set list1[1] = 2003 where p1 = 'key1';").discard_result();
|
|
}).then([&e, my_list_type] {
|
|
return e.require_column_has_value("cf", {sstring("key1")}, {},
|
|
"list1", make_list_value(my_list_type, list_type_impl::native_type({1002, 2003})));
|
|
}).then([&e] {
|
|
return e.execute_cql("update cf set list1 = list1 - [1002, 2004] where p1 = 'key1';").discard_result();
|
|
}).then([&e, my_list_type] {
|
|
return e.require_column_has_value("cf", {sstring("key1")}, {},
|
|
"list1", make_list_value(my_list_type, list_type_impl::native_type({{2003}})));
|
|
}).then([&e, my_list_type] {
|
|
return e.execute_cql("select * from cf where p1 = 'key1';").then([my_list_type] (shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows()
|
|
.with_size(1)
|
|
.with_row({
|
|
{utf8_type->decompose(sstring("key1"))},
|
|
{my_list_type->decompose(make_list_value(my_list_type, list_type_impl::native_type({{2003}})))},
|
|
});
|
|
});
|
|
}).then([&e] {
|
|
return e.execute_cql("update cf set list1 = [2008, 2009, 2010] where p1 = 'key1';").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("delete list1[1] from cf where p1 = 'key1';").discard_result();
|
|
}).then([&e, my_list_type] {
|
|
return e.require_column_has_value("cf", {sstring("key1")}, {},
|
|
"list1", make_list_value(my_list_type, list_type_impl::native_type({2008, 2010})));
|
|
}).then([&e] {
|
|
return e.execute_cql("update cf set list1 = list1 + [2012, 2019] where p1 = 'key1';").discard_result();
|
|
}).then([&e, my_list_type] {
|
|
return e.require_column_has_value("cf", {sstring("key1")}, {},
|
|
"list1", make_list_value(my_list_type, list_type_impl::native_type({2008, 2010, 2012, 2019})));
|
|
}).then([&e] {
|
|
return e.execute_cql("update cf set list1 = [2001, 2002] + list1 where p1 = 'key1';").discard_result();
|
|
}).then([&e, my_list_type] {
|
|
return e.require_column_has_value("cf", {sstring("key1")}, {},
|
|
"list1", make_list_value(my_list_type, list_type_impl::native_type({2001, 2002, 2008, 2010, 2012, 2019})));
|
|
}).then([&e] {
|
|
return e.execute_cql("insert into cf (p1, list1) values ('key1', null);").discard_result();
|
|
}).then([&e, my_list_type] {
|
|
return e.require_column_has_value("cf", {sstring("key1")}, {},
|
|
"list1", make_list_value(my_list_type, list_type_impl::native_type({})));
|
|
});
|
|
});
|
|
}
|
|
|
|
SEASTAR_TEST_CASE(test_functions) {
|
|
return do_with_cql_env([] (cql_test_env& e) {
|
|
return e.create_table([](sstring ks_name) {
|
|
// CQL: create table cf (p1 varchar primary key, u uuid, tu timeuuid);
|
|
return schema({}, ks_name, "cf",
|
|
{{"p1", utf8_type}}, {{"c1", int32_type}}, {{"tu", timeuuid_type}}, {}, utf8_type);
|
|
}).then([&e] {
|
|
return e.execute_cql("insert into cf (p1, c1, tu) values ('key1', 1, now());").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("insert into cf (p1, c1, tu) values ('key1', 2, now());").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("insert into cf (p1, c1, tu) values ('key1', 3, now());").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("select tu from cf where p1 in ('key1');");
|
|
}).then([&e] (shared_ptr<cql_transport::messages::result_message> msg) {
|
|
using namespace cql_transport::messages;
|
|
struct validator : result_message::visitor {
|
|
std::vector<bytes_opt> res;
|
|
virtual void visit(const result_message::void_message&) override { throw "bad"; }
|
|
virtual void visit(const result_message::set_keyspace&) override { throw "bad"; }
|
|
virtual void visit(const result_message::prepared::cql&) override { throw "bad"; }
|
|
virtual void visit(const result_message::prepared::thrift&) override { throw "bad"; }
|
|
virtual void visit(const result_message::schema_change&) override { throw "bad"; }
|
|
virtual void visit(const result_message::rows& rows) override {
|
|
auto rs = rows.rs().result_set();
|
|
BOOST_REQUIRE_EQUAL(rs.rows().size(), 3);
|
|
for (auto&& rw : rs.rows()) {
|
|
BOOST_REQUIRE_EQUAL(rw.size(), 1);
|
|
res.push_back(rw[0]);
|
|
}
|
|
}
|
|
};
|
|
validator v;
|
|
msg->accept(v);
|
|
// No boost::adaptors::sorted
|
|
boost::sort(v.res);
|
|
BOOST_REQUIRE_EQUAL(boost::distance(v.res | boost::adaptors::uniqued), 3);
|
|
}).then([&] {
|
|
return e.execute_cql("select sum(c1), count(c1) from cf where p1 = 'key1';");
|
|
}).then([&e] (shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows()
|
|
.with_size(1)
|
|
.with_row({
|
|
{int32_type->decompose(6)},
|
|
{long_type->decompose(3L)},
|
|
});
|
|
}).then([&] {
|
|
return e.execute_cql("select count(*) from cf where p1 = 'key1';");
|
|
}).then([&e] (shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows()
|
|
.with_size(1)
|
|
.with_row({
|
|
{long_type->decompose(3L)},
|
|
});
|
|
}).then([&] {
|
|
return e.execute_cql("select count(1) from cf where p1 = 'key1';");
|
|
}).then([&e] (shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows()
|
|
.with_size(1)
|
|
.with_row({
|
|
{long_type->decompose(3L)},
|
|
});
|
|
}).then([&e] {
|
|
// Inane, casting to own type, but couldn't find more interesting example
|
|
return e.execute_cql("insert into cf (p1, c1) values ((text)'key2', 7);").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("select c1 from cf where p1 = 'key2';");
|
|
}).then([&e] (shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows()
|
|
.with_size(1)
|
|
.with_row({
|
|
{int32_type->decompose(7)},
|
|
});
|
|
});
|
|
});
|
|
}
|
|
|
|
static const api::timestamp_type the_timestamp = 123456789;
|
|
SEASTAR_TEST_CASE(test_writetime_and_ttl) {
|
|
return do_with_cql_env([] (cql_test_env& e) {
|
|
return e.execute_cql("create table cf (p1 varchar primary key, i int, fc frozen<set<int>>, c set<int>);").discard_result().then([&e] {
|
|
auto q = format("insert into cf (p1, i) values ('key1', 1) using timestamp {:d};", the_timestamp);
|
|
return e.execute_cql(q).discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("select writetime(i) from cf where p1 in ('key1');");
|
|
}).then([&e] (shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows()
|
|
.with_rows({{
|
|
{long_type->decompose(int64_t(the_timestamp))},
|
|
}});
|
|
}).then([&e] {
|
|
return async([&e] {
|
|
auto ts1 = the_timestamp + 1;
|
|
e.execute_cql(format("UPDATE cf USING TIMESTAMP {:d} SET fc = {{1}}, c = {{2}} WHERE p1 = 'key1'", ts1)).get();
|
|
auto msg1 = e.execute_cql("SELECT writetime(fc) FROM cf").get0();
|
|
assert_that(msg1).is_rows()
|
|
.with_rows({{
|
|
{long_type->decompose(int64_t(ts1))},
|
|
}});
|
|
auto msg2f = futurize_apply([&] { return e.execute_cql("SELECT writetime(c) FROM cf"); });
|
|
msg2f.wait();
|
|
assert_that_failed(msg2f);
|
|
});
|
|
});
|
|
});
|
|
}
|
|
|
|
SEASTAR_TEST_CASE(test_batch) {
|
|
return do_with_cql_env([] (cql_test_env& e) {
|
|
return e.execute_cql("create table cf (p1 varchar, c1 int, r1 int, PRIMARY KEY (p1, c1));").discard_result().then([&e] {
|
|
return e.execute_cql(
|
|
"begin unlogged batch \n"
|
|
" insert into cf (p1, c1, r1) values ('key1', 1, 100); \n"
|
|
" insert into cf (p1, c1, r1) values ('key1', 2, 200); \n"
|
|
"apply batch;"
|
|
).discard_result();
|
|
}).then([&e] {
|
|
return e.require_column_has_value("cf", {sstring("key1")}, {1}, "r1", 100);
|
|
}).then([&e] {
|
|
return e.require_column_has_value("cf", {sstring("key1")}, {2}, "r1", 200);
|
|
});
|
|
});
|
|
}
|
|
|
|
SEASTAR_TEST_CASE(test_tuples) {
|
|
auto make_tt = [] { return tuple_type_impl::get_instance({int32_type, long_type, utf8_type}); };
|
|
auto tt = make_tt();
|
|
return do_with_cql_env([tt, make_tt] (cql_test_env& e) {
|
|
return e.create_table([make_tt] (sstring ks_name) {
|
|
// this runs on all cores, so create a local tt for each core:
|
|
auto tt = make_tt();
|
|
// CQL: "create table cf (id int primary key, t tuple<int, bigint, text>);
|
|
return schema({}, ks_name, "cf",
|
|
{{"id", int32_type}}, {}, {{"t", tt}}, {}, utf8_type);
|
|
}).then([&e] {
|
|
return e.execute_cql("insert into cf (id, t) values (1, (1001, 2001, 'abc1'));").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("select t from cf where id = 1;");
|
|
}).then([&e, tt] (shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows()
|
|
.with_rows({{
|
|
{tt->decompose(make_tuple_value(tt, tuple_type_impl::native_type({int32_t(1001), int64_t(2001), sstring("abc1")})))},
|
|
}});
|
|
return e.execute_cql("create table cf2 (p1 int PRIMARY KEY, r1 tuple<int, bigint, text>)").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("insert into cf2 (p1, r1) values (1, (1, 2, 'abc'));").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("select * from cf2 where p1 = 1;");
|
|
}).then([&e, tt] (shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().with_rows({
|
|
{ int32_type->decompose(int32_t(1)), tt->decompose(make_tuple_value(tt, tuple_type_impl::native_type({int32_t(1), int64_t(2), sstring("abc")}))) }
|
|
});
|
|
});
|
|
});
|
|
}
|
|
|
|
SEASTAR_TEST_CASE(test_user_type) {
|
|
return do_with_cql_env([] (cql_test_env& e) {
|
|
return e.execute_cql("create type ut1 (my_int int, my_bigint bigint, my_text text);").discard_result().then([&e] {
|
|
return e.execute_cql("create table cf (id int primary key, t frozen <ut1>);").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("insert into cf (id, t) values (1, (1001, 2001, 'abc1'));").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("select t.my_int, t.my_bigint, t.my_text from cf where id = 1;");
|
|
}).then([&e] (shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows()
|
|
.with_rows({
|
|
{int32_type->decompose(int32_t(1001)), long_type->decompose(int64_t(2001)), utf8_type->decompose(sstring("abc1"))},
|
|
});
|
|
}).then([&e] {
|
|
return e.execute_cql("update cf set t = { my_int: 1002, my_bigint: 2002, my_text: 'abc2' } where id = 1;").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("select t.my_int, t.my_bigint, t.my_text from cf where id = 1;");
|
|
}).then([&e] (shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows()
|
|
.with_rows({
|
|
{int32_type->decompose(int32_t(1002)), long_type->decompose(int64_t(2002)), utf8_type->decompose(sstring("abc2"))},
|
|
});
|
|
}).then([&e] {
|
|
return e.execute_cql("insert into cf (id, t) values (2, (frozen<ut1>)(2001, 3001, 'abc4'));").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("select t from cf where id = 2;");
|
|
}).then([&e] (shared_ptr<cql_transport::messages::result_message> msg) {
|
|
auto ut = user_type_impl::get_instance("ks", to_bytes("ut1"),
|
|
{to_bytes("my_int"), to_bytes("my_bigint"), to_bytes("my_text")},
|
|
{int32_type, long_type, utf8_type});
|
|
auto ut_val = make_user_value(ut,
|
|
user_type_impl::native_type({int32_t(2001),
|
|
int64_t(3001),
|
|
sstring("abc4")}));
|
|
assert_that(msg).is_rows()
|
|
.with_rows({
|
|
{ut->decompose(ut_val)},
|
|
});
|
|
});
|
|
});
|
|
}
|
|
|
|
//
|
|
// Since durations don't have a well-defined ordering on their semantic value, a number of restrictions exist on their
|
|
// use.
|
|
//
|
|
SEASTAR_TEST_CASE(test_duration_restrictions) {
|
|
auto validate_request_failure = [] (cql_test_env& env, const sstring& request, const sstring& expected_message) {
|
|
return futurize_apply([&] { return env.execute_cql(request); }).then_wrapped([expected_message] (future<shared_ptr<cql_transport::messages::result_message>> f) {
|
|
BOOST_REQUIRE_EXCEPTION(f.get(),
|
|
exceptions::invalid_request_exception,
|
|
[&expected_message](const exceptions::invalid_request_exception& ire) {
|
|
BOOST_REQUIRE_EQUAL(expected_message, ire.what());
|
|
return true;
|
|
});
|
|
});
|
|
};
|
|
|
|
return do_with_cql_env([&] (cql_test_env& env) {
|
|
return make_ready_future<>().then([&] {
|
|
// Disallow "direct" use of durations in ordered collection types to avoid user confusion when their
|
|
// ordering doesn't match expectations.
|
|
return make_ready_future<>().then([&] {
|
|
return validate_request_failure(
|
|
env,
|
|
"create type my_type (a set<duration>);",
|
|
"Durations are not allowed inside sets: set<duration>");
|
|
}).then([&] {
|
|
return validate_request_failure(
|
|
env,
|
|
"create type my_type (a map<duration, int>);",
|
|
"Durations are not allowed as map keys: map<duration, int>");
|
|
});
|
|
}).then([&] {
|
|
// Disallow any type referring to a duration from being used in a primary key of a table or a materialized
|
|
// view.
|
|
return make_ready_future<>().then([&] {
|
|
return validate_request_failure(
|
|
env,
|
|
"create table my_table (direct_key duration PRIMARY KEY);",
|
|
"duration type is not supported for PRIMARY KEY part direct_key");
|
|
}).then([&] {
|
|
return validate_request_failure(
|
|
env,
|
|
"create table my_table (collection_key frozen<list<duration>> PRIMARY KEY);",
|
|
"duration type is not supported for PRIMARY KEY part collection_key");
|
|
}).then([&] {
|
|
return env.execute_cql("create type my_type0 (span duration);").discard_result().then([&] {
|
|
return validate_request_failure(
|
|
env,
|
|
"create table my_table (udt_key frozen<my_type0> PRIMARY KEY);",
|
|
"duration type is not supported for PRIMARY KEY part udt_key");
|
|
});
|
|
}).then([&] {
|
|
return validate_request_failure(
|
|
env,
|
|
"create table my_table (tuple_key tuple<int, duration, int> PRIMARY KEY);",
|
|
"duration type is not supported for PRIMARY KEY part tuple_key");
|
|
}).then([&] {
|
|
return env.execute_cql("create table my_table0 (key int PRIMARY KEY, name text, span duration);")
|
|
.discard_result().then([&] {
|
|
return validate_request_failure(
|
|
env,
|
|
"create materialized view my_mv as"
|
|
" select * from my_table0 "
|
|
" primary key (key, span);",
|
|
"Cannot use Duration column 'span' in PRIMARY KEY of materialized view");
|
|
});
|
|
});
|
|
}).then([&] {
|
|
// Disallow creating secondary indexes on durations.
|
|
return validate_request_failure(
|
|
env,
|
|
"create index my_index on my_table0 (span);",
|
|
"Secondary indexes are not supported on duration columns");
|
|
}).then([&] {
|
|
// Disallow slice-based restrictions and conditions on durations.
|
|
//
|
|
// Note that multi-column restrictions are only supported on clustering columns (which cannot be `duration`)
|
|
// and that multi-column conditions are not supported in the grammar.
|
|
return make_ready_future<>().then([&] {
|
|
return validate_request_failure(
|
|
env,
|
|
"select * from my_table0 where key = 0 and span < 3d;",
|
|
"Slice restrictions are not supported on duration columns");
|
|
}).then([&] {
|
|
return validate_request_failure(
|
|
env,
|
|
"update my_table0 set name = 'joe' where key = 0 if span >= 5m",
|
|
"Slice conditions are not supported on durations");
|
|
});
|
|
});
|
|
});
|
|
}
|
|
|
|
SEASTAR_TEST_CASE(test_select_multiple_ranges) {
|
|
return do_with_cql_env([] (cql_test_env& e) {
|
|
return e.execute_cql("create table cf (p1 varchar, r1 int, PRIMARY KEY (p1));").discard_result().then([&e] {
|
|
return e.execute_cql(
|
|
"begin unlogged batch \n"
|
|
" insert into cf (p1, r1) values ('key1', 100); \n"
|
|
" insert into cf (p1, r1) values ('key2', 200); \n"
|
|
"apply batch;"
|
|
).discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("select r1 from cf where p1 in ('key1', 'key2');");
|
|
}).then([&e] (shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().with_size(2).with_row({
|
|
{int32_type->decompose(100)}
|
|
}).with_row({
|
|
{int32_type->decompose(200)}
|
|
});
|
|
|
|
});
|
|
});
|
|
}
|
|
|
|
SEASTAR_TEST_CASE(test_validate_keyspace) {
|
|
return do_with_cql_env([] (cql_test_env& e) {
|
|
return make_ready_future<>().then([&e] {
|
|
return e.execute_cql("create keyspace kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkssssssssssssssssssssssssssssssssssssssssssssss with replication = { 'class' : 'SimpleStrategy', 'replication_factor' : 1 };");
|
|
}).then_wrapped([&e] (future<shared_ptr<cql_transport::messages::result_message>> f) {
|
|
assert_that_failed(f);
|
|
return e.execute_cql("create keyspace ks3-1 with replication = { 'class' : 'SimpleStrategy', 'replication_factor' : 1 };");
|
|
}).then_wrapped([&e] (future<shared_ptr<cql_transport::messages::result_message>> f) {
|
|
assert_that_failed(f);
|
|
return e.execute_cql("create keyspace ks3 with replication = { 'replication_factor' : 1 };");
|
|
}).then_wrapped([&e] (future<shared_ptr<cql_transport::messages::result_message>> f) {
|
|
assert_that_failed(f);
|
|
return e.execute_cql("create keyspace ks3 with rreplication = { 'class' : 'SimpleStrategy', 'replication_factor' : 1 };");
|
|
}).then_wrapped([&e] (future<shared_ptr<cql_transport::messages::result_message>> f) {
|
|
assert_that_failed(f);
|
|
return e.execute_cql("create keyspace SyStEm with replication = { 'class' : 'SimpleStrategy', 'replication_factor' : 1 };");
|
|
}).then_wrapped([&e] (future<shared_ptr<cql_transport::messages::result_message>> f) {
|
|
assert_that_failed(f);
|
|
});
|
|
});
|
|
}
|
|
|
|
SEASTAR_TEST_CASE(test_validate_table) {
|
|
return do_with_cql_env([] (cql_test_env& e) {
|
|
return make_ready_future<>().then([&e] {
|
|
return e.execute_cql("create table ttttttttttttttttttttttttttttttttttttttttbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb (foo text PRIMARY KEY, bar text);");
|
|
}).then_wrapped([&e] (future<shared_ptr<cql_transport::messages::result_message>> f) {
|
|
assert_that_failed(f);
|
|
return e.execute_cql("create table tb (foo text PRIMARY KEY, foo text);");
|
|
}).then_wrapped([&e] (future<shared_ptr<cql_transport::messages::result_message>> f) {
|
|
assert_that_failed(f);
|
|
return e.execute_cql("create table tb-1 (foo text PRIMARY KEY, bar text);");
|
|
}).then_wrapped([&e] (future<shared_ptr<cql_transport::messages::result_message>> f) {
|
|
assert_that_failed(f);
|
|
return e.execute_cql("create table tb (foo text, bar text);");
|
|
}).then_wrapped([&e] (future<shared_ptr<cql_transport::messages::result_message>> f) {
|
|
assert_that_failed(f);
|
|
return e.execute_cql("create table tb (foo text PRIMARY KEY, bar text PRIMARY KEY);");
|
|
}).then_wrapped([&e] (future<shared_ptr<cql_transport::messages::result_message>> f) {
|
|
assert_that_failed(f);
|
|
return e.execute_cql("create table tb (foo text PRIMARY KEY, bar text) with commment = 'aaaa';");
|
|
}).then_wrapped([&e] (future<shared_ptr<cql_transport::messages::result_message>> f) {
|
|
assert_that_failed(f);
|
|
return e.execute_cql("create table tb (foo text PRIMARY KEY, bar text) with min_index_interval = -1;");
|
|
}).then_wrapped([&e] (future<shared_ptr<cql_transport::messages::result_message>> f) {
|
|
assert_that_failed(f);
|
|
return e.execute_cql("create table tb (foo text PRIMARY KEY, bar text) with min_index_interval = 1024 and max_index_interval = 128;");
|
|
}).then_wrapped([&e] (future<shared_ptr<cql_transport::messages::result_message>> f) {
|
|
assert_that_failed(f);
|
|
});
|
|
});
|
|
}
|
|
|
|
SEASTAR_TEST_CASE(test_table_compression) {
|
|
return do_with_cql_env([] (cql_test_env& e) {
|
|
return make_ready_future<>().then([&e] {
|
|
return e.execute_cql("create table tb1 (foo text PRIMARY KEY, bar text) with compression = { };");
|
|
}).then_wrapped([&e] (future<shared_ptr<cql_transport::messages::result_message>> f) {
|
|
assert(!f.failed());
|
|
e.require_table_exists("ks", "tb1");
|
|
BOOST_REQUIRE(e.local_db().find_schema("ks", "tb1")->get_compressor_params().get_compressor() == nullptr);
|
|
return e.execute_cql("create table tb5 (foo text PRIMARY KEY, bar text) with compression = { 'sstable_compression' : '' };");
|
|
}).then_wrapped([&e] (future<shared_ptr<cql_transport::messages::result_message>> f) {
|
|
assert(!f.failed());
|
|
e.require_table_exists("ks", "tb5");
|
|
BOOST_REQUIRE(e.local_db().find_schema("ks", "tb5")->get_compressor_params().get_compressor() == nullptr);
|
|
return e.execute_cql("create table tb2 (foo text PRIMARY KEY, bar text) with compression = { 'sstable_compression' : 'LossyCompressor' };");
|
|
}).then_wrapped([&e] (future<shared_ptr<cql_transport::messages::result_message>> f) {
|
|
assert_that_failed(f);
|
|
return e.execute_cql("create table tb2 (foo text PRIMARY KEY, bar text) with compression = { 'sstable_compression' : 'LZ4Compressor', 'chunk_length_kb' : -1 };");
|
|
}).then_wrapped([&e] (future<shared_ptr<cql_transport::messages::result_message>> f) {
|
|
assert_that_failed(f);
|
|
return e.execute_cql("create table tb2 (foo text PRIMARY KEY, bar text) with compression = { 'sstable_compression' : 'LZ4Compressor', 'chunk_length_kb' : 3 };");
|
|
}).then_wrapped([&e] (future<shared_ptr<cql_transport::messages::result_message>> f) {
|
|
assert_that_failed(f);
|
|
return e.execute_cql("create table tb2 (foo text PRIMARY KEY, bar text) with compression = { 'sstable_compression' : 'LZ4Compressor', 'chunk_length_kb' : 2 };");
|
|
}).then_wrapped([&e] (future<shared_ptr<cql_transport::messages::result_message>> f) {
|
|
assert(!f.failed());
|
|
e.require_table_exists("ks", "tb2");
|
|
BOOST_REQUIRE(e.local_db().find_schema("ks", "tb2")->get_compressor_params().get_compressor() == compressor::lz4);
|
|
BOOST_REQUIRE(e.local_db().find_schema("ks", "tb2")->get_compressor_params().chunk_length() == 2 * 1024);
|
|
return e.execute_cql("create table tb3 (foo text PRIMARY KEY, bar text) with compression = { 'sstable_compression' : 'DeflateCompressor' };");
|
|
}).then_wrapped([&e] (future<shared_ptr<cql_transport::messages::result_message>> f) {
|
|
assert(!f.failed());
|
|
e.require_table_exists("ks", "tb3");
|
|
BOOST_REQUIRE(e.local_db().find_schema("ks", "tb3")->get_compressor_params().get_compressor() == compressor::deflate);
|
|
return e.execute_cql("create table tb4 (foo text PRIMARY KEY, bar text) with compression = { 'sstable_compression' : 'org.apache.cassandra.io.compress.DeflateCompressor' };");
|
|
}).then_wrapped([&e] (future<shared_ptr<cql_transport::messages::result_message>> f) {
|
|
assert(!f.failed());
|
|
e.require_table_exists("ks", "tb4");
|
|
BOOST_REQUIRE(e.local_db().find_schema("ks", "tb4")->get_compressor_params().get_compressor() == compressor::deflate);
|
|
return e.execute_cql("create table tb6 (foo text PRIMARY KEY, bar text);");
|
|
}).then([&e] (shared_ptr<cql_transport::messages::result_message> msg) {
|
|
e.require_table_exists("ks", "tb6");
|
|
BOOST_REQUIRE(e.local_db().find_schema("ks", "tb6")->get_compressor_params().get_compressor() == compressor::lz4);
|
|
});
|
|
});
|
|
}
|
|
|
|
SEASTAR_TEST_CASE(test_ttl) {
|
|
return do_with_cql_env([] (cql_test_env& e) {
|
|
auto make_my_list_type = [] { return list_type_impl::get_instance(utf8_type, true); };
|
|
auto my_list_type = make_my_list_type();
|
|
return e.create_table([make_my_list_type] (sstring ks_name) {
|
|
return schema({}, ks_name, "cf",
|
|
{{"p1", utf8_type}}, {}, {{"r1", utf8_type}, {"r2", utf8_type}, {"r3", make_my_list_type()}}, {}, utf8_type);
|
|
}).then([&e] {
|
|
return e.execute_cql(
|
|
"update cf using ttl 100000 set r1 = 'value1_1', r3 = ['a', 'b', 'c'] where p1 = 'key1';").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql(
|
|
"update cf using ttl 100 set r1 = 'value1_3', r3 = ['a', 'b', 'c'] where p1 = 'key3';").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("update cf using ttl 100 set r3[1] = 'b' where p1 = 'key1';").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("update cf using ttl 100 set r1 = 'value1_2' where p1 = 'key2';").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("insert into cf (p1, r2) values ('key2', 'value2_2');").discard_result();
|
|
}).then([&e, my_list_type] {
|
|
return e.execute_cql("select r1 from cf;").then([](shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().with_size(3)
|
|
.with_row({utf8_type->decompose(sstring("value1_1"))})
|
|
.with_row({utf8_type->decompose(sstring("value1_2"))})
|
|
.with_row({utf8_type->decompose(sstring("value1_3"))});
|
|
});
|
|
}).then([&e, my_list_type] {
|
|
return e.execute_cql("select r3 from cf where p1 = 'key1';").then([my_list_type] (shared_ptr<cql_transport::messages::result_message> msg) {
|
|
auto my_list_type = list_type_impl::get_instance(utf8_type, true);
|
|
assert_that(msg).is_rows().with_rows({
|
|
{my_list_type->decompose(make_list_value(my_list_type, list_type_impl::native_type{{sstring("a"), sstring("b"), sstring("c")}}))}
|
|
});
|
|
});
|
|
}).then([&e] {
|
|
forward_jump_clocks(200s);
|
|
return e.execute_cql("select r1, r2 from cf;").then([](shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().with_size(2)
|
|
.with_row({{}, utf8_type->decompose(sstring("value2_2"))})
|
|
.with_row({utf8_type->decompose(sstring("value1_1")), {}});
|
|
});
|
|
}).then([&e] {
|
|
return e.execute_cql("select r2 from cf;").then([] (shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().with_size(2)
|
|
.with_row({ utf8_type->decompose(sstring("value2_2")) })
|
|
.with_row({ {} });
|
|
});
|
|
}).then([&e] {
|
|
return e.execute_cql("select r1 from cf;").then([] (shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().with_size(2)
|
|
.with_row({ {} })
|
|
.with_row({ utf8_type->decompose(sstring("value1_1")) });
|
|
});
|
|
}).then([&e, my_list_type] {
|
|
return e.execute_cql("select r3 from cf where p1 = 'key1';").then([] (shared_ptr<cql_transport::messages::result_message> msg) {
|
|
auto my_list_type = list_type_impl::get_instance(utf8_type, true);
|
|
assert_that(msg).is_rows().with_rows({
|
|
{my_list_type->decompose(make_list_value(my_list_type, list_type_impl::native_type{{sstring("a"), sstring("c")}}))}
|
|
});
|
|
});
|
|
}).then([&e] {
|
|
return e.execute_cql("create table cf2 (p1 text PRIMARY KEY, r1 text, r2 text);").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("insert into cf2 (p1, r1) values ('foo', 'bar') using ttl 500;").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("select p1, r1 from cf2 where p1 = 'foo';").then([] (shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().with_rows({
|
|
{utf8_type->decompose(sstring("foo")), utf8_type->decompose(sstring("bar"))}
|
|
});
|
|
});
|
|
}).then([&e] {
|
|
forward_jump_clocks(600s);
|
|
return e.execute_cql("select p1, r1 from cf2 where p1 = 'foo';").then([] (shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().with_rows({ });
|
|
});
|
|
}).then([&e] {
|
|
return e.execute_cql("select p1, r1 from cf2;").then([] (shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().with_rows({ });
|
|
});
|
|
}).then([&e] {
|
|
return e.execute_cql("select count(*) from cf2;").then([] (shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().with_rows({
|
|
{long_type->decompose(int64_t(0))}
|
|
});
|
|
});
|
|
}).then([&e] {
|
|
return e.execute_cql("insert into cf2 (p1, r1) values ('foo', 'bar') using ttl 500;").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("update cf2 set r1 = null where p1 = 'foo';").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("select p1, r1 from cf2 where p1 = 'foo';").then([] (shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().with_rows({
|
|
{utf8_type->decompose(sstring("foo")), { }}
|
|
});
|
|
});
|
|
}).then([&e] {
|
|
forward_jump_clocks(600s);
|
|
return e.execute_cql("select p1, r1 from cf2 where p1 = 'foo';").then([] (shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().with_rows({ });
|
|
});
|
|
}).then([&e] {
|
|
return e.execute_cql("insert into cf2 (p1, r1) values ('foo', 'bar') using ttl 500;").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("insert into cf2 (p1, r2) values ('foo', null);").discard_result();
|
|
}).then([&e] {
|
|
forward_jump_clocks(600s);
|
|
return e.execute_cql("select p1, r1 from cf2 where p1 = 'foo';").then([] (shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().with_rows({
|
|
{utf8_type->decompose(sstring("foo")), { }}
|
|
});
|
|
});
|
|
});
|
|
});
|
|
}
|
|
|
|
SEASTAR_TEST_CASE(test_types) {
|
|
return do_with_cql_env([] (cql_test_env& e) {
|
|
return make_ready_future<>().then([&e] {
|
|
return e.execute_cql(
|
|
"CREATE TABLE all_types ("
|
|
" a ascii PRIMARY KEY,"
|
|
" b bigint,"
|
|
" c blob,"
|
|
" d boolean,"
|
|
" e double,"
|
|
" f float,"
|
|
" g inet,"
|
|
" h int,"
|
|
" i text,"
|
|
" j timestamp,"
|
|
" k timeuuid,"
|
|
" l uuid,"
|
|
" m varchar,"
|
|
" n varint,"
|
|
" o decimal,"
|
|
" p tinyint,"
|
|
" q smallint,"
|
|
" r date,"
|
|
" s time,"
|
|
" u duration,"
|
|
");").discard_result();
|
|
}).then([&e] {
|
|
e.require_table_exists("ks", "all_types");
|
|
return e.execute_cql(
|
|
"INSERT INTO all_types (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, u) VALUES ("
|
|
" 'ascii',"
|
|
" 123456789,"
|
|
" 0xdeadbeef,"
|
|
" true,"
|
|
" 3.14,"
|
|
" 3.14,"
|
|
" '127.0.0.1',"
|
|
" 3,"
|
|
" 'zażółć gęślą jaźń',"
|
|
" '2001-10-18 14:15:55.134+0000',"
|
|
" d2177dd0-eaa2-11de-a572-001b779c76e3,"
|
|
" d2177dd0-eaa2-11de-a572-001b779c76e3,"
|
|
" 'varchar',"
|
|
" 123,"
|
|
" 1.23,"
|
|
" 3,"
|
|
" 3,"
|
|
" '1970-01-02',"
|
|
" '00:00:00.000000001',"
|
|
" 1y2mo3w4d5h6m7s8ms9us10ns"
|
|
");").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("SELECT * FROM all_types WHERE a = 'ascii'");
|
|
}).then([&e] (shared_ptr<cql_transport::messages::result_message> msg) {
|
|
struct tm t = { 0 };
|
|
t.tm_year = 2001 - 1900;
|
|
t.tm_mon = 10 - 1;
|
|
t.tm_mday = 18;
|
|
t.tm_hour = 14;
|
|
t.tm_min = 15;
|
|
t.tm_sec = 55;
|
|
auto tp = db_clock::from_time_t(timegm(&t)) + std::chrono::milliseconds(134);
|
|
assert_that(msg).is_rows().with_rows({
|
|
{
|
|
ascii_type->decompose(sstring("ascii")), long_type->decompose(123456789l),
|
|
from_hex("deadbeef"), boolean_type->decompose(true),
|
|
double_type->decompose(3.14), float_type->decompose(3.14f),
|
|
inet_addr_type->decompose(net::inet_address("127.0.0.1")),
|
|
int32_type->decompose(3), utf8_type->decompose(sstring("zażółć gęślą jaźń")),
|
|
timestamp_type->decompose(tp),
|
|
timeuuid_type->decompose(utils::UUID(sstring("d2177dd0-eaa2-11de-a572-001b779c76e3"))),
|
|
uuid_type->decompose(utils::UUID(sstring("d2177dd0-eaa2-11de-a572-001b779c76e3"))),
|
|
utf8_type->decompose(sstring("varchar")), varint_type->decompose(boost::multiprecision::cpp_int(123)),
|
|
decimal_type->decompose(big_decimal { 2, boost::multiprecision::cpp_int(123) }),
|
|
byte_type->decompose(int8_t(3)),
|
|
short_type->decompose(int16_t(3)),
|
|
simple_date_type->decompose(int32_t(0x80000001)),
|
|
time_type->decompose(int64_t(0x0000000000000001)),
|
|
duration_type->decompose(cql_duration("1y2mo3w4d5h6m7s8ms9us10ns"))
|
|
}
|
|
});
|
|
return e.execute_cql(
|
|
"INSERT INTO all_types (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, u) VALUES ("
|
|
" blobAsAscii(asciiAsBlob('ascii2')),"
|
|
" blobAsBigint(bigintAsBlob(123456789)),"
|
|
" bigintAsBlob(12),"
|
|
" blobAsBoolean(booleanAsBlob(true)),"
|
|
" blobAsDouble(doubleAsBlob(3.14)),"
|
|
" blobAsFloat(floatAsBlob(3.14)),"
|
|
" blobAsInet(inetAsBlob('127.0.0.1')),"
|
|
" blobAsInt(intAsBlob(3)),"
|
|
" blobAsText(textAsBlob('zażółć gęślą jaźń')),"
|
|
" blobAsTimestamp(timestampAsBlob('2001-10-18 14:15:55.134+0000')),"
|
|
" blobAsTimeuuid(timeuuidAsBlob(d2177dd0-eaa2-11de-a572-001b779c76e3)),"
|
|
" blobAsUuid(uuidAsBlob(d2177dd0-eaa2-11de-a572-001b779c76e3)),"
|
|
" blobAsVarchar(varcharAsBlob('varchar')), blobAsVarint(varintAsBlob(123)),"
|
|
" blobAsDecimal(decimalAsBlob(1.23)),"
|
|
" blobAsTinyint(tinyintAsBlob(3)),"
|
|
" blobAsSmallint(smallintAsBlob(3)),"
|
|
" blobAsDate(dateAsBlob('1970-01-02')),"
|
|
" blobAsTime(timeAsBlob('00:00:00.000000001')),"
|
|
" blobAsDuration(durationAsBlob(10y9mo8w7d6h5m4s3ms2us1ns))"
|
|
");").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("SELECT * FROM all_types WHERE a = 'ascii2'");
|
|
}).then([&e] (shared_ptr<cql_transport::messages::result_message> msg) {
|
|
struct tm t = {0};
|
|
t.tm_year = 2001 - 1900;
|
|
t.tm_mon = 10 - 1;
|
|
t.tm_mday = 18;
|
|
t.tm_hour = 14;
|
|
t.tm_min = 15;
|
|
t.tm_sec = 55;
|
|
auto tp = db_clock::from_time_t(timegm(&t)) + std::chrono::milliseconds(134);
|
|
assert_that(msg).is_rows().with_rows({
|
|
{
|
|
ascii_type->decompose(sstring("ascii2")), long_type->decompose(123456789l),
|
|
from_hex("000000000000000c"), boolean_type->decompose(true),
|
|
double_type->decompose(3.14), float_type->decompose(3.14f),
|
|
inet_addr_type->decompose(net::inet_address("127.0.0.1")),
|
|
int32_type->decompose(3), utf8_type->decompose(sstring("zażółć gęślą jaźń")),
|
|
timestamp_type->decompose(tp),
|
|
timeuuid_type->decompose(utils::UUID(sstring("d2177dd0-eaa2-11de-a572-001b779c76e3"))),
|
|
uuid_type->decompose(utils::UUID(sstring("d2177dd0-eaa2-11de-a572-001b779c76e3"))),
|
|
utf8_type->decompose(sstring("varchar")), varint_type->decompose(boost::multiprecision::cpp_int(123)),
|
|
decimal_type->decompose(big_decimal { 2, boost::multiprecision::cpp_int(123) }),
|
|
byte_type->decompose(int8_t(3)),
|
|
short_type->decompose(int16_t(3)),
|
|
simple_date_type->decompose(int32_t(0x80000001)),
|
|
time_type->decompose(int64_t(0x0000000000000001)),
|
|
duration_type->decompose(cql_duration("10y9mo8w7d6h5m4s3ms2us1ns"))
|
|
}
|
|
});
|
|
});
|
|
});
|
|
}
|
|
|
|
SEASTAR_TEST_CASE(test_order_by) {
|
|
return do_with_cql_env([] (cql_test_env& e) {
|
|
return e.execute_cql("create table torder (p1 int, c1 int, c2 int, r1 int, r2 int, PRIMARY KEY(p1, c1, c2));").discard_result().then([&e] {
|
|
e.require_table_exists("ks", "torder");
|
|
return e.execute_cql("insert into torder (p1, c1, c2, r1) values (0, 1, 2, 3);").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("insert into torder (p1, c1, c2, r1) values (0, 2, 1, 0);").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("select c1, c2, r1 from torder where p1 = 0 order by c1 asc;");
|
|
}).then([&e] (shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().with_rows({
|
|
{int32_type->decompose(1), int32_type->decompose(2), int32_type->decompose(3)},
|
|
{int32_type->decompose(2), int32_type->decompose(1), int32_type->decompose(0)},
|
|
});
|
|
return e.execute_cql("select c1, c2, r1 from torder where p1 = 0 order by c1 desc;");
|
|
}).then([&e] (shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().with_rows({
|
|
{int32_type->decompose(2), int32_type->decompose(1), int32_type->decompose(0)},
|
|
{int32_type->decompose(1), int32_type->decompose(2), int32_type->decompose(3)},
|
|
});
|
|
return e.execute_cql("insert into torder (p1, c1, c2, r1) values (0, 1, 1, 4);").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("insert into torder (p1, c1, c2, r1) values (0, 2, 2, 5);").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("select c1, c2, r1 from torder where p1 = 0 order by c1 desc, c2 desc;");
|
|
}).then([&e] (shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().with_rows({
|
|
{int32_type->decompose(2), int32_type->decompose(2), int32_type->decompose(5)},
|
|
{int32_type->decompose(2), int32_type->decompose(1), int32_type->decompose(0)},
|
|
{int32_type->decompose(1), int32_type->decompose(2), int32_type->decompose(3)},
|
|
{int32_type->decompose(1), int32_type->decompose(1), int32_type->decompose(4)},
|
|
});
|
|
return e.execute_cql("insert into torder (p1, c1, c2, r1) values (1, 1, 0, 6);").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("insert into torder (p1, c1, c2, r1) values (1, 2, 3, 7);").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("select c1, c2, r1 from torder where p1 in (0, 1) order by c1 desc, c2 desc;");
|
|
}).then([&e] (shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().with_rows({
|
|
{int32_type->decompose(2), int32_type->decompose(3), int32_type->decompose(7)},
|
|
{int32_type->decompose(2), int32_type->decompose(2), int32_type->decompose(5)},
|
|
{int32_type->decompose(2), int32_type->decompose(1), int32_type->decompose(0)},
|
|
{int32_type->decompose(1), int32_type->decompose(2), int32_type->decompose(3)},
|
|
{int32_type->decompose(1), int32_type->decompose(1), int32_type->decompose(4)},
|
|
{int32_type->decompose(1), int32_type->decompose(0), int32_type->decompose(6)},
|
|
});
|
|
}).then([&e] {
|
|
return e.execute_cql("select c1, c2, r1 from torder where p1 in (0, 1) order by c1 asc, c2 asc;");
|
|
}).then([&e] (shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().with_rows({
|
|
{int32_type->decompose(1), int32_type->decompose(0), int32_type->decompose(6)},
|
|
{int32_type->decompose(1), int32_type->decompose(1), int32_type->decompose(4)},
|
|
{int32_type->decompose(1), int32_type->decompose(2), int32_type->decompose(3)},
|
|
{int32_type->decompose(2), int32_type->decompose(1), int32_type->decompose(0)},
|
|
{int32_type->decompose(2), int32_type->decompose(2), int32_type->decompose(5)},
|
|
{int32_type->decompose(2), int32_type->decompose(3), int32_type->decompose(7)},
|
|
});
|
|
return e.execute_cql("select c1, c2, r1 from torder where p1 in (0, 1) and c1 < 2 order by c1 desc, c2 desc limit 1;");
|
|
}).then([&e] (shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().with_rows({
|
|
{int32_type->decompose(1), int32_type->decompose(2), int32_type->decompose(3)},
|
|
});
|
|
return e.execute_cql("select c1, c2, r1 from torder where p1 in (0, 1) and c1 >= 2 order by c1 asc, c2 asc limit 1;");
|
|
}).then([&e] (shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().with_rows({
|
|
{int32_type->decompose(2), int32_type->decompose(1), int32_type->decompose(0)},
|
|
});
|
|
return e.execute_cql("select c1, c2, r1 from torder where p1 in (0, 1) order by c1 desc, c2 desc limit 1;");
|
|
}).then([&e] (shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().with_rows({
|
|
{int32_type->decompose(2), int32_type->decompose(3), int32_type->decompose(7)},
|
|
});
|
|
return e.execute_cql("select c1, c2, r1 from torder where p1 in (0, 1) order by c1 asc, c2 asc limit 1;");
|
|
}).then([&e] (shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().with_rows({
|
|
{int32_type->decompose(1), int32_type->decompose(0), int32_type->decompose(6)},
|
|
});
|
|
return e.execute_cql("select c1, c2, r1 from torder where p1 = 0 and c1 > 1 order by c1 desc, c2 desc;");
|
|
}).then([&e] (shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().with_rows({
|
|
{int32_type->decompose(2), int32_type->decompose(2), int32_type->decompose(5)},
|
|
{int32_type->decompose(2), int32_type->decompose(1), int32_type->decompose(0)},
|
|
});
|
|
return e.execute_cql("select c1, c2, r1 from torder where p1 = 0 and c1 >= 2 order by c1 desc, c2 desc;");
|
|
}).then([&e] (shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().with_rows({
|
|
{int32_type->decompose(2), int32_type->decompose(2), int32_type->decompose(5)},
|
|
{int32_type->decompose(2), int32_type->decompose(1), int32_type->decompose(0)},
|
|
});
|
|
return e.execute_cql("select c1, c2, r1 from torder where p1 = 0 and c1 >= 2 order by c1 desc, c2 desc limit 1;");
|
|
}).then([&e] (shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().with_rows({
|
|
{int32_type->decompose(2), int32_type->decompose(2), int32_type->decompose(5)},
|
|
});
|
|
return e.execute_cql("select c1, c2, r1 from torder where p1 = 0 order by c1 desc, c2 desc limit 1;");
|
|
}).then([&e] (shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().with_rows({
|
|
{int32_type->decompose(2), int32_type->decompose(2), int32_type->decompose(5)},
|
|
});
|
|
return e.execute_cql("select c1, c2, r1 from torder where p1 = 0 and c1 > 1 order by c1 asc, c2 asc;");
|
|
}).then([&e] (shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().with_rows({
|
|
{int32_type->decompose(2), int32_type->decompose(1), int32_type->decompose(0)},
|
|
{int32_type->decompose(2), int32_type->decompose(2), int32_type->decompose(5)},
|
|
});
|
|
return e.execute_cql("select c1, c2, r1 from torder where p1 = 0 and c1 >= 2 order by c1 asc, c2 asc;");
|
|
}).then([&e] (shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().with_rows({
|
|
{int32_type->decompose(2), int32_type->decompose(1), int32_type->decompose(0)},
|
|
{int32_type->decompose(2), int32_type->decompose(2), int32_type->decompose(5)},
|
|
});
|
|
return e.execute_cql("select c1, c2, r1 from torder where p1 = 0 and c1 >= 2 order by c1 asc, c2 asc limit 1;");
|
|
}).then([&e] (shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().with_rows({
|
|
{int32_type->decompose(2), int32_type->decompose(1), int32_type->decompose(0)},
|
|
});
|
|
return e.execute_cql("select c1, c2, r1 from torder where p1 = 0 order by c1 asc, c2 asc limit 1;");
|
|
}).then([&e] (shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().with_rows({
|
|
{int32_type->decompose(1), int32_type->decompose(1), int32_type->decompose(4)},
|
|
});
|
|
});
|
|
});
|
|
}
|
|
|
|
SEASTAR_TEST_CASE(test_order_by_validate) {
|
|
return do_with_cql_env([] (cql_test_env& e) {
|
|
return e.execute_cql("create table torderv (p1 int, c1 int, c2 int, r1 int, r2 int, PRIMARY KEY(p1, c1, c2));").discard_result().then([&e] {
|
|
return e.execute_cql("select c2, r1 from torderv where p1 = 0 order by c desc;");
|
|
}).then_wrapped([&e] (future<shared_ptr<cql_transport::messages::result_message>> f) {
|
|
assert_that_failed(f);
|
|
return e.execute_cql("select c2, r1 from torderv where p1 = 0 order by c2 desc;");
|
|
}).then_wrapped([&e] (future<shared_ptr<cql_transport::messages::result_message>> f) {
|
|
assert_that_failed(f);
|
|
return e.execute_cql("select c2, r1 from torderv where p1 = 0 order by c1 desc, c2 asc;");
|
|
}).then_wrapped([&e] (future<shared_ptr<cql_transport::messages::result_message>> f) {
|
|
assert_that_failed(f);
|
|
return e.execute_cql("select c2, r1 from torderv order by c1 asc;");
|
|
}).then_wrapped([] (future<shared_ptr<cql_transport::messages::result_message>> f) {
|
|
assert_that_failed(f);
|
|
});
|
|
});
|
|
}
|
|
|
|
SEASTAR_TEST_CASE(test_multi_column_restrictions) {
|
|
return do_with_cql_env([] (cql_test_env& e) {
|
|
return e.execute_cql("create table tmcr (p1 int, c1 int, c2 int, c3 int, r1 int, PRIMARY KEY (p1, c1, c2, c3));").discard_result().then([&e] {
|
|
e.require_table_exists("ks", "tmcr");
|
|
return e.execute_cql("insert into tmcr (p1, c1, c2, c3, r1) values (0, 0, 0, 0, 0);").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("insert into tmcr (p1, c1, c2, c3, r1) values (0, 0, 0, 1, 1);").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("insert into tmcr (p1, c1, c2, c3, r1) values (0, 0, 1, 0, 2);").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("insert into tmcr (p1, c1, c2, c3, r1) values (0, 0, 1, 1, 3);").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("insert into tmcr (p1, c1, c2, c3, r1) values (0, 1, 0, 0, 4);").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("insert into tmcr (p1, c1, c2, c3, r1) values (0, 1, 0, 1, 5);").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("insert into tmcr (p1, c1, c2, c3, r1) values (0, 1, 1, 0, 6);").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("insert into tmcr (p1, c1, c2, c3, r1) values (0, 1, 1, 1, 7);").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("select r1 from tmcr where p1 = 0 and (c1, c2, c3) = (0, 1, 1);");
|
|
}).then([&e] (shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().with_rows({
|
|
{int32_type->decompose(3)},
|
|
});
|
|
return e.execute_cql("select r1 from tmcr where p1 = 0 and (c1, c2) = (0, 1);");
|
|
}).then([&e] (shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().with_rows({
|
|
{int32_type->decompose(2)},
|
|
{int32_type->decompose(3)},
|
|
});
|
|
return e.execute_cql("select r1 from tmcr where p1 = 0 and (c1, c2, c3) in ((0, 1, 0), (1, 0, 1), (0, 1, 0));");
|
|
}).then([&e] (shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().with_rows({
|
|
{int32_type->decompose(2)},
|
|
{int32_type->decompose(5)},
|
|
});
|
|
return e.execute_cql("select r1 from tmcr where p1 = 0 and (c1, c2) in ((0, 1), (1, 0), (0, 1));");
|
|
}).then([&e] (shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().with_rows({
|
|
{int32_type->decompose(2)},
|
|
{int32_type->decompose(3)},
|
|
{int32_type->decompose(4)},
|
|
{int32_type->decompose(5)},
|
|
});
|
|
return e.execute_cql("select r1 from tmcr where p1 = 0 and (c1, c2, c3) >= (1, 0, 1);");
|
|
}).then([&e] (shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().with_rows({
|
|
{int32_type->decompose(5)},
|
|
{int32_type->decompose(6)},
|
|
{int32_type->decompose(7)},
|
|
});
|
|
return e.execute_cql("select r1 from tmcr where p1 = 0 and (c1, c2, c3) >= (0, 1, 1) and (c1, c2, c3) < (1, 1, 0);");
|
|
}).then([&e] (shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().with_rows({
|
|
{int32_type->decompose(3)},
|
|
{int32_type->decompose(4)},
|
|
{int32_type->decompose(5)},
|
|
});
|
|
return e.execute_cql("select r1 from tmcr where p1 = 0 and (c1, c2) >= (0, 1) and (c1, c2, c3) < (1, 0, 1);");
|
|
}).then([&e] (shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().with_rows({
|
|
{int32_type->decompose(2)},
|
|
{int32_type->decompose(3)},
|
|
{int32_type->decompose(4)},
|
|
});
|
|
return e.execute_cql("select r1 from tmcr where p1 = 0 and (c1, c2, c3) > (0, 1, 0) and (c1, c2) <= (0, 1);");
|
|
}).then([&e] (shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().with_rows({
|
|
{int32_type->decompose(3)},
|
|
});
|
|
});
|
|
});
|
|
}
|
|
|
|
SEASTAR_TEST_CASE(test_select_distinct) {
|
|
return do_with_cql_env([] (cql_test_env& e) {
|
|
return e.execute_cql("create table tsd (p1 int, c1 int, r1 int, PRIMARY KEY (p1, c1));").discard_result().then([&e] {
|
|
e.require_table_exists("ks", "tsd");
|
|
return e.execute_cql("insert into tsd (p1, c1, r1) values (0, 0, 0);").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("insert into tsd (p1, c1, r1) values (1, 1, 1);").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("insert into tsd (p1, c1, r1) values (1, 1, 2);").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("insert into tsd (p1, c1, r1) values (2, 2, 2);").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("insert into tsd (p1, c1, r1) values (2, 3, 3);").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("select distinct p1 from tsd;");
|
|
}).then([&e] (shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().with_size(3)
|
|
.with_row({int32_type->decompose(0)})
|
|
.with_row({int32_type->decompose(1)})
|
|
.with_row({int32_type->decompose(2)});
|
|
return e.execute_cql("select distinct p1 from tsd limit 3;");
|
|
}).then([&e] (shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().with_size(3)
|
|
.with_row({int32_type->decompose(0)})
|
|
.with_row({int32_type->decompose(1)})
|
|
.with_row({int32_type->decompose(2)});
|
|
return e.execute_cql("create table tsd2 (p1 int, p2 int, c1 int, r1 int, PRIMARY KEY ((p1, p2), c1));").discard_result();
|
|
}).then([&e] {
|
|
e.require_table_exists("ks", "tsd2");
|
|
return e.execute_cql("insert into tsd2 (p1, p2, c1, r1) values (0, 0, 0, 0);").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("insert into tsd2 (p1, p2, c1, r1) values (0, 0, 1, 1);").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("insert into tsd2 (p1, p2, c1, r1) values (1, 1, 0, 0);").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("insert into tsd2 (p1, p2, c1, r1) values (1, 1, 1, 1);").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("insert into tsd2 (p1, p2, c1, r1) values (2, 2, 0, 0);").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("insert into tsd2 (p1, p2, c1, r1) values (2, 2, 1, 1);").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("select distinct p1, p2 from tsd2;");
|
|
}).then([&e] (shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().with_size(3)
|
|
.with_row({int32_type->decompose(0), int32_type->decompose(0)})
|
|
.with_row({int32_type->decompose(1), int32_type->decompose(1)})
|
|
.with_row({int32_type->decompose(2), int32_type->decompose(2)});
|
|
return e.execute_cql("select distinct p1, p2 from tsd2 limit 3;");
|
|
}).then([&e] (shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().with_size(3)
|
|
.with_row({int32_type->decompose(0), int32_type->decompose(0)})
|
|
.with_row({int32_type->decompose(1), int32_type->decompose(1)})
|
|
.with_row({int32_type->decompose(2), int32_type->decompose(2)});
|
|
return e.execute_cql("create table tsd3 (p1 int, r1 int, PRIMARY KEY (p1));").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("insert into tsd3 (p1, r1) values (0, 0);").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("insert into tsd3 (p1, r1) values (1, 1);").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("insert into tsd3 (p1, r1) values (1, 2);").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("insert into tsd3 (p1, r1) values (2, 2);").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("select distinct p1 from tsd3;");
|
|
}).then([&e] (shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().with_size(3)
|
|
.with_row({int32_type->decompose(0)})
|
|
.with_row({int32_type->decompose(1)})
|
|
.with_row({int32_type->decompose(2)});
|
|
return e.execute_cql("create table tsd4 (p1 int, c1 int, s1 int static, r1 int, PRIMARY KEY (p1, c1));").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("insert into tsd4 (p1, c1, s1, r1) values (0, 0, 0, 0);").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("insert into tsd4 (p1, c1, r1) values (0, 1, 1);").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("insert into tsd4 (p1, s1) values (2, 1);").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("insert into tsd4 (p1, s1) values (3, 2);").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("select distinct p1, s1 from tsd4;");
|
|
}).then([&e] (shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().with_size(3)
|
|
.with_row({int32_type->decompose(0), int32_type->decompose(0)})
|
|
.with_row({int32_type->decompose(2), int32_type->decompose(1)})
|
|
.with_row({int32_type->decompose(3), int32_type->decompose(2)});
|
|
});
|
|
});
|
|
}
|
|
|
|
SEASTAR_TEST_CASE(test_select_distinct_with_where_clause) {
|
|
return do_with_cql_env([] (cql_test_env& e) {
|
|
return seastar::async([&e] {
|
|
e.execute_cql("CREATE TABLE cf (k int, a int, b int, PRIMARY KEY (k, a))").get();
|
|
for (int i = 0; i < 10; i++) {
|
|
e.execute_cql(format("INSERT INTO cf (k, a, b) VALUES ({:d}, {:d}, {:d})", i, i, i)).get();
|
|
e.execute_cql(format("INSERT INTO cf (k, a, b) VALUES ({:d}, {:d}, {:d})", i, i * 10, i * 10)).get();
|
|
}
|
|
BOOST_REQUIRE_THROW(e.execute_cql("SELECT DISTINCT k FROM cf WHERE a >= 80 ALLOW FILTERING").get(), std::exception);
|
|
BOOST_REQUIRE_THROW(e.execute_cql("SELECT DISTINCT k FROM cf WHERE k IN (1, 2, 3) AND a = 10").get(), std::exception);
|
|
BOOST_REQUIRE_THROW(e.execute_cql("SELECT DISTINCT k FROM cf WHERE b = 5").get(), std::exception);
|
|
|
|
assert_that(e.execute_cql("SELECT DISTINCT k FROM cf WHERE k = 1").get0())
|
|
.is_rows().with_size(1)
|
|
.with_row({int32_type->decompose(1)});
|
|
|
|
assert_that(e.execute_cql("SELECT DISTINCT k FROM cf WHERE k IN (5, 6, 7)").get0())
|
|
.is_rows().with_size(3)
|
|
.with_row({int32_type->decompose(5)})
|
|
.with_row({int32_type->decompose(6)})
|
|
.with_row({int32_type->decompose(7)});
|
|
|
|
// static columns
|
|
e.execute_cql("CREATE TABLE cf2 (k int, a int, s int static, b int, PRIMARY KEY (k, a))").get();
|
|
for (int i = 0; i < 10; i++) {
|
|
e.execute_cql(format("INSERT INTO cf2 (k, a, b, s) VALUES ({:d}, {:d}, {:d}, {:d})", i, i, i, i)).get();
|
|
e.execute_cql(format("INSERT INTO cf2 (k, a, b, s) VALUES ({:d}, {:d}, {:d}, {:d})", i, i * 10, i * 10, i * 10)).get();
|
|
}
|
|
assert_that(e.execute_cql("SELECT DISTINCT s FROM cf2 WHERE k = 5").get0())
|
|
.is_rows().with_size(1)
|
|
.with_row({int32_type->decompose(50)});
|
|
|
|
assert_that(e.execute_cql("SELECT DISTINCT s FROM cf2 WHERE k IN (5, 6, 7)").get0())
|
|
.is_rows().with_size(3)
|
|
.with_row({int32_type->decompose(50)})
|
|
.with_row({int32_type->decompose(60)})
|
|
.with_row({int32_type->decompose(70)});
|
|
});
|
|
});
|
|
}
|
|
|
|
SEASTAR_TEST_CASE(test_batch_insert_statement) {
|
|
return do_with_cql_env([] (cql_test_env& e) {
|
|
return e.execute_cql("create table cf (p1 varchar, c1 int, r1 int, PRIMARY KEY (p1, c1));").discard_result().then([&e] {
|
|
return e.execute_cql(R"(BEGIN BATCH
|
|
insert into cf (p1, c1, r1) values ('key1', 1, 100);
|
|
insert into cf (p1, c1, r1) values ('key2', 2, 200);
|
|
APPLY BATCH;)"
|
|
).discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql(R"(BEGIN BATCH
|
|
update cf set r1 = 66 where p1 = 'key1' and c1 = 1;
|
|
update cf set r1 = 33 where p1 = 'key2' and c1 = 2;
|
|
APPLY BATCH;)"
|
|
).discard_result();
|
|
|
|
}).then([&e] {
|
|
return e.require_column_has_value("cf", {sstring("key1")}, {1}, "r1", 66);
|
|
}).then([&e] {
|
|
return e.require_column_has_value("cf", {sstring("key2")}, {2}, "r1", 33);
|
|
});
|
|
});
|
|
}
|
|
|
|
SEASTAR_TEST_CASE(test_in_restriction) {
|
|
return do_with_cql_env([] (cql_test_env& e) {
|
|
return e.execute_cql("create table tir (p1 int, c1 int, r1 int, PRIMARY KEY (p1, c1));").discard_result().then([&e] {
|
|
e.require_table_exists("ks", "tir");
|
|
return e.execute_cql("insert into tir (p1, c1, r1) values (0, 0, 0);").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("insert into tir (p1, c1, r1) values (1, 0, 1);").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("insert into tir (p1, c1, r1) values (1, 1, 2);").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("insert into tir (p1, c1, r1) values (1, 2, 3);").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("insert into tir (p1, c1, r1) values (2, 3, 4);").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("select * from tir where p1 in ();");
|
|
}).then([&e] (shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().with_size(0);
|
|
return e.execute_cql("select r1 from tir where p1 in (2, 0, 2, 1);");
|
|
}).then([&e] (shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().with_rows_ignore_order({
|
|
{int32_type->decompose(4)},
|
|
{int32_type->decompose(0)},
|
|
{int32_type->decompose(1)},
|
|
{int32_type->decompose(2)},
|
|
{int32_type->decompose(3)},
|
|
});
|
|
return e.execute_cql("select r1 from tir where p1 = 1 and c1 in ();");
|
|
}).then([&e] (shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().with_size(0);
|
|
return e.execute_cql("select r1 from tir where p1 = 1 and c1 in (2, 0, 2, 1);");
|
|
}).then([&e] (shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().with_rows({
|
|
{int32_type->decompose(1)},
|
|
{int32_type->decompose(2)},
|
|
{int32_type->decompose(3)},
|
|
});
|
|
return e.execute_cql("select r1 from tir where p1 = 1 and c1 in (2, 0, 2, 1) order by c1 desc;");
|
|
}).then([&e] (shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().with_rows({
|
|
{int32_type->decompose(3)},
|
|
{int32_type->decompose(2)},
|
|
{int32_type->decompose(1)},
|
|
});
|
|
return e.prepare("select r1 from tir where p1 in ?;");
|
|
}).then([&e] (cql3::prepared_cache_key_type prepared_id){
|
|
auto my_list_type = list_type_impl::get_instance(int32_type, true);
|
|
std::vector<cql3::raw_value> raw_values;
|
|
auto in_values_list = my_list_type->decompose(make_list_value(my_list_type,
|
|
list_type_impl::native_type{{int(2), int(0), int(2), int(1)}}));
|
|
raw_values.emplace_back(cql3::raw_value::make_value(in_values_list));
|
|
return e.execute_prepared(prepared_id,raw_values);
|
|
}).then([&e] (shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().with_rows_ignore_order({
|
|
{int32_type->decompose(4)},
|
|
{int32_type->decompose(0)},
|
|
{int32_type->decompose(1)},
|
|
{int32_type->decompose(2)},
|
|
{int32_type->decompose(3)},
|
|
});
|
|
}).then([&e]{
|
|
return e.execute_cql("create table tir2 (p1 int, c1 int, r1 int, PRIMARY KEY (p1, c1,r1));").discard_result();
|
|
}).then([&e] {
|
|
e.require_table_exists("ks", "tir2");
|
|
return e.execute_cql("insert into tir2 (p1, c1, r1) values (0, 0, 0);").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("insert into tir2 (p1, c1, r1) values (1, 0, 1);").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("insert into tir2 (p1, c1, r1) values (1, 1, 2);").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("insert into tir2 (p1, c1, r1) values (1, 2, 3);").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("insert into tir2 (p1, c1, r1) values (2, 3, 4);").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("select r1 from tir2 where (c1,r1) in ((0, 1),(1,2),(0,1),(1,2),(3,3)) ALLOW FILTERING;");
|
|
}).then([&e] (shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().with_rows_ignore_order({
|
|
{int32_type->decompose(1)},
|
|
{int32_type->decompose(2)},
|
|
});
|
|
}).then([&e] {
|
|
return e.prepare("select r1 from tir2 where (c1,r1) in ? ALLOW FILTERING;");
|
|
}).then([&e] (cql3::prepared_cache_key_type prepared_id) {
|
|
auto my_tuple_type = tuple_type_impl::get_instance({int32_type,int32_type});
|
|
auto my_list_type = list_type_impl::get_instance(my_tuple_type, true);
|
|
std::vector<tuple_type_impl::native_type> native_tuples = {
|
|
{int(0), int(1)},
|
|
{int(1), int(2)},
|
|
{int(0), int(1)},
|
|
{int(1), int(2)},
|
|
{int(3), int(3)},
|
|
};
|
|
std::vector<data_value> tuples;
|
|
for (auto&& native_tuple : native_tuples ) {
|
|
tuples.emplace_back(make_tuple_value(my_tuple_type,native_tuple));
|
|
}
|
|
|
|
std::vector<cql3::raw_value> raw_values;
|
|
auto in_values_list = my_list_type->decompose(make_list_value(my_list_type,tuples));
|
|
raw_values.emplace_back(cql3::raw_value::make_value(in_values_list));
|
|
return e.execute_prepared(prepared_id,raw_values);
|
|
}).then([&e] (shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().with_rows_ignore_order({
|
|
{int32_type->decompose(1)},
|
|
{int32_type->decompose(2)},
|
|
});
|
|
});
|
|
});
|
|
}
|
|
|
|
SEASTAR_TEST_CASE(test_compact_storage) {
|
|
return do_with_cql_env([] (cql_test_env& e) {
|
|
return e.execute_cql("create table tcs (p1 int, c1 int, r1 int, PRIMARY KEY (p1, c1)) with compact storage;").discard_result().then([&e] {
|
|
return e.require_table_exists("ks", "tcs");
|
|
}).then([&e] {
|
|
return e.execute_cql("insert into tcs (p1, c1, r1) values (1, 2, 3);").discard_result();
|
|
}).then([&e] {
|
|
return e.require_column_has_value("tcs", {1}, {2}, "r1", 3);
|
|
}).then([&e] {
|
|
return e.execute_cql("update tcs set r1 = 4 where p1 = 1 and c1 = 2;").discard_result();
|
|
}).then([&e] {
|
|
return e.require_column_has_value("tcs", {1}, {2}, "r1", 4);
|
|
}).then([&e] {
|
|
return e.execute_cql("select * from tcs where p1 = 1;");
|
|
}).then([&e] (shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().with_rows({
|
|
{ int32_type->decompose(1), int32_type->decompose(2), int32_type->decompose(4) },
|
|
});
|
|
return e.execute_cql("create table tcs2 (p1 int, c1 int, PRIMARY KEY (p1, c1)) with compact storage;").discard_result();
|
|
}).then([&e] {
|
|
return e.require_table_exists("ks", "tcs2");
|
|
}).then([&e] {
|
|
return e.execute_cql("insert into tcs2 (p1, c1) values (1, 2);").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("select * from tcs2 where p1 = 1;");
|
|
}).then([&e] (shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().with_rows({
|
|
{ int32_type->decompose(1), int32_type->decompose(2) },
|
|
});
|
|
return e.execute_cql("create table tcs3 (p1 int, c1 int, c2 int, r1 int, PRIMARY KEY (p1, c1, c2)) with compact storage;").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("insert into tcs3 (p1, c1, c2, r1) values (1, 2, 3, 4);").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("insert into tcs3 (p1, c1, r1) values (1, 2, 5);").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("insert into tcs3 (p1, c1, r1) values (1, 3, 6);").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("insert into tcs3 (p1, c1, c2, r1) values (1, 3, 5, 7);").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("insert into tcs3 (p1, c1, c2, r1) values (1, 3, blobasint(0x), 8);").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("select * from tcs3 where p1 = 1;");
|
|
}).then([&e] (shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().with_rows({
|
|
{ int32_type->decompose(1), int32_type->decompose(2), {}, int32_type->decompose(5) },
|
|
{ int32_type->decompose(1), int32_type->decompose(2), int32_type->decompose(3), int32_type->decompose(4) },
|
|
{ int32_type->decompose(1), int32_type->decompose(3), {}, int32_type->decompose(6) },
|
|
{ int32_type->decompose(1), int32_type->decompose(3), bytes(), int32_type->decompose(8) },
|
|
{ int32_type->decompose(1), int32_type->decompose(3), int32_type->decompose(5), int32_type->decompose(7) },
|
|
});
|
|
return e.execute_cql("delete from tcs3 where p1 = 1 and c1 = 2;").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("select * from tcs3 where p1 = 1;");
|
|
}).then([&e] (shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().with_rows({
|
|
{ int32_type->decompose(1), int32_type->decompose(3), {}, int32_type->decompose(6) },
|
|
{ int32_type->decompose(1), int32_type->decompose(3), bytes(), int32_type->decompose(8) },
|
|
{ int32_type->decompose(1), int32_type->decompose(3), int32_type->decompose(5), int32_type->decompose(7) },
|
|
});
|
|
return e.execute_cql("delete from tcs3 where p1 = 1 and c1 = 3 and c2 = 5;").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("select * from tcs3 where p1 = 1;");
|
|
}).then([&e] (shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().with_rows({
|
|
{ int32_type->decompose(1), int32_type->decompose(3), {}, int32_type->decompose(6) },
|
|
{ int32_type->decompose(1), int32_type->decompose(3), bytes(), int32_type->decompose(8) },
|
|
});
|
|
return e.execute_cql("delete from tcs3 where p1 = 1 and c1 = 3 and c2 = blobasint(0x);").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("select * from tcs3 where p1 = 1;");
|
|
}).then([&e] (shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().with_rows({
|
|
{ int32_type->decompose(1), int32_type->decompose(3), {}, int32_type->decompose(6) },
|
|
});
|
|
return e.execute_cql("create table tcs4 (p1 int PRIMARY KEY, c1 int, c2 int) with compact storage;").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("insert into tcs4 (p1) values (1);").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("select * from tcs4;");
|
|
}).then([&e] (shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().with_rows({ });
|
|
});
|
|
});
|
|
}
|
|
|
|
SEASTAR_TEST_CASE(test_collections_of_collections) {
|
|
return do_with_cql_env([] (cql_test_env& e) {
|
|
auto set_of_ints = set_type_impl::get_instance(int32_type, true);
|
|
auto set_of_sets = set_type_impl::get_instance(set_of_ints, true);
|
|
auto map_of_sets = map_type_impl::get_instance(set_of_ints, int32_type, true);
|
|
return e.execute_cql("create table cf_sos (p1 int PRIMARY KEY, v set<frozen<set<int>>>);").discard_result().then([&e] {
|
|
return e.execute_cql("insert into cf_sos (p1, v) values (1, {{1, 2}, {3, 4}, {5, 6}});").discard_result();
|
|
}).then([&e, set_of_sets, set_of_ints] {
|
|
return e.require_column_has_value("cf_sos", {1}, {},
|
|
"v", make_set_value(set_of_sets, set_type_impl::native_type({
|
|
make_set_value(set_of_ints, set_type_impl::native_type({1, 2})),
|
|
make_set_value(set_of_ints, set_type_impl::native_type({3, 4})),
|
|
make_set_value(set_of_ints, set_type_impl::native_type({5, 6})),
|
|
})));
|
|
}).then([&e, set_of_sets, set_of_ints] {
|
|
return e.execute_cql("delete v[{3, 4}] from cf_sos where p1 = 1;").discard_result();
|
|
}).then([&e, set_of_sets, set_of_ints] {
|
|
return e.require_column_has_value("cf_sos", {1}, {},
|
|
"v", make_set_value(set_of_sets, set_type_impl::native_type({
|
|
make_set_value(set_of_ints, set_type_impl::native_type({1, 2})),
|
|
make_set_value(set_of_ints, set_type_impl::native_type({5, 6})),
|
|
})));
|
|
}).then([&e, set_of_sets, set_of_ints] {
|
|
return e.execute_cql("update cf_sos set v = v - {{1, 2}, {5}} where p1 = 1;").discard_result();
|
|
}).then([&e, set_of_sets, set_of_ints] {
|
|
return e.require_column_has_value("cf_sos", {1}, {},
|
|
"v", make_set_value(set_of_sets, set_type_impl::native_type({
|
|
make_set_value(set_of_ints, set_type_impl::native_type({5, 6})),
|
|
})));
|
|
}).then([&e] {
|
|
return e.execute_cql("create table cf_mos (p1 int PRIMARY KEY, v map<frozen<set<int>>, int>);").discard_result();
|
|
}).then([&e, map_of_sets, set_of_ints] {
|
|
return e.execute_cql("insert into cf_mos (p1, v) values (1, {{1, 2}: 7, {3, 4}: 8, {5, 6}: 9});").discard_result();
|
|
}).then([&e, map_of_sets, set_of_ints] {
|
|
return e.require_column_has_value("cf_mos", {1}, {},
|
|
"v", make_map_value(map_of_sets, map_type_impl::native_type({
|
|
{ make_set_value(set_of_ints, set_type_impl::native_type({1, 2})), 7 },
|
|
{ make_set_value(set_of_ints, set_type_impl::native_type({3, 4})), 8 },
|
|
{ make_set_value(set_of_ints, set_type_impl::native_type({5, 6})), 9 },
|
|
})));
|
|
}).then([&e, map_of_sets, set_of_ints] {
|
|
return e.execute_cql("delete v[{3, 4}] from cf_mos where p1 = 1;").discard_result();
|
|
}).then([&e, map_of_sets, set_of_ints] {
|
|
return e.require_column_has_value("cf_mos", {1}, {},
|
|
"v", make_map_value(map_of_sets, map_type_impl::native_type({
|
|
{ make_set_value(set_of_ints, set_type_impl::native_type({1, 2})), 7 },
|
|
{ make_set_value(set_of_ints, set_type_impl::native_type({5, 6})), 9 },
|
|
})));
|
|
}).then([&e, map_of_sets, set_of_ints] {
|
|
return e.execute_cql("update cf_mos set v = v - {{1, 2}, {5}} where p1 = 1;").discard_result();
|
|
}).then([&e, map_of_sets, set_of_ints] {
|
|
return e.require_column_has_value("cf_mos", {1}, {},
|
|
"v", make_map_value(map_of_sets, map_type_impl::native_type({
|
|
{ make_set_value(set_of_ints, set_type_impl::native_type({5, 6})), 9 },
|
|
})));
|
|
});
|
|
});
|
|
}
|
|
|
|
|
|
SEASTAR_TEST_CASE(test_result_order) {
|
|
return do_with_cql_env([] (cql_test_env& e) {
|
|
return e.execute_cql("create table tro (p1 int, c1 text, r1 int, PRIMARY KEY (p1, c1)) with compact storage;").discard_result().then([&e] {
|
|
return e.execute_cql("insert into tro (p1, c1, r1) values (1, 'z', 1);").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("insert into tro (p1, c1, r1) values (1, 'bbbb', 2);").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("insert into tro (p1, c1, r1) values (1, 'a', 3);").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("insert into tro (p1, c1, r1) values (1, 'aaa', 4);").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("insert into tro (p1, c1, r1) values (1, 'bb', 5);").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("insert into tro (p1, c1, r1) values (1, 'cccc', 6);").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("select * from tro where p1 = 1;");
|
|
}).then([&e] (shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().with_rows({
|
|
{ int32_type->decompose(1), utf8_type->decompose(sstring("a")), int32_type->decompose(3) },
|
|
{ int32_type->decompose(1), utf8_type->decompose(sstring("aaa")), int32_type->decompose(4) },
|
|
{ int32_type->decompose(1), utf8_type->decompose(sstring("bb")), int32_type->decompose(5) },
|
|
{ int32_type->decompose(1), utf8_type->decompose(sstring("bbbb")), int32_type->decompose(2) },
|
|
{ int32_type->decompose(1), utf8_type->decompose(sstring("cccc")), int32_type->decompose(6) },
|
|
{ int32_type->decompose(1), utf8_type->decompose(sstring("z")), int32_type->decompose(1) },
|
|
});
|
|
});
|
|
});
|
|
}
|
|
|
|
SEASTAR_TEST_CASE(test_frozen_collections) {
|
|
return do_with_cql_env([] (cql_test_env& e) {
|
|
auto set_of_ints = set_type_impl::get_instance(int32_type, false);
|
|
auto list_of_ints = list_type_impl::get_instance(int32_type, false);
|
|
auto frozen_map_of_set_and_list = map_type_impl::get_instance(set_of_ints, list_of_ints, false);
|
|
return e.execute_cql("CREATE TABLE tfc (a int, b int, c frozen<map<set<int>, list<int>>> static, d int, PRIMARY KEY (a, b));").discard_result().then([&e] {
|
|
return e.execute_cql("INSERT INTO tfc (a, b, c, d) VALUES (0, 0, {}, 0);").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("SELECT * FROM tfc;");
|
|
}).then([&e, frozen_map_of_set_and_list] (shared_ptr<cql_transport::messages::result_message> msg) {
|
|
map_type_impl::mutation_view empty_mv{};
|
|
assert_that(msg).is_rows().with_rows({
|
|
{ int32_type->decompose(0), int32_type->decompose(0), frozen_map_of_set_and_list->to_value(empty_mv, cql_serialization_format::internal()), int32_type->decompose(0) },
|
|
});
|
|
});
|
|
});
|
|
}
|
|
|
|
|
|
SEASTAR_TEST_CASE(test_alter_table) {
|
|
return do_with_cql_env([] (cql_test_env& e) {
|
|
return e.execute_cql("create table tat (pk1 int, c1 int, ck2 int, r1 int, r2 int, PRIMARY KEY (pk1, c1, ck2));").discard_result().then([&e] {
|
|
return e.execute_cql("insert into tat (pk1, c1, ck2, r1, r2) values (1, 2, 3, 4, 5);").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("alter table tat with comment = 'This is a comment.';").discard_result();
|
|
}).then([&e] {
|
|
BOOST_REQUIRE_EQUAL(e.local_db().find_schema("ks", "tat")->comment(), sstring("This is a comment."));
|
|
return e.execute_cql("alter table tat alter r2 type blob;").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("select pk1, c1, ck2, r1, r2 from tat;");
|
|
}).then([&e] (shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().with_rows({
|
|
{ int32_type->decompose(1), int32_type->decompose(2), int32_type->decompose(3), int32_type->decompose(4), int32_type->decompose(5) },
|
|
});
|
|
}).then([&e] {
|
|
return e.execute_cql("insert into tat (pk1, c1, ck2, r2) values (1, 2, 3, 0x1234567812345678);").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("select pk1, c1, ck2, r1, r2 from tat;");
|
|
}).then([&e] (shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().with_rows({
|
|
{ int32_type->decompose(1), int32_type->decompose(2), int32_type->decompose(3), int32_type->decompose(4), from_hex("1234567812345678") },
|
|
});
|
|
}).then([&e] {
|
|
return e.execute_cql("alter table tat rename pk1 to p1 and ck2 to c2;").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("select p1, c1, c2, r1, r2 from tat;");
|
|
}).then([&e] (shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().with_rows({
|
|
{ int32_type->decompose(1), int32_type->decompose(2), int32_type->decompose(3), int32_type->decompose(4), from_hex("1234567812345678") },
|
|
});
|
|
return e.execute_cql("alter table tat add r1_2 int;").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("insert into tat (p1, c1, c2, r1_2) values (1, 2, 3, 6);").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("select * from tat;");
|
|
}).then([&e] (shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().with_rows({
|
|
{ int32_type->decompose(1), int32_type->decompose(2), int32_type->decompose(3), int32_type->decompose(4), int32_type->decompose(6), from_hex("1234567812345678") },
|
|
});
|
|
return e.execute_cql("alter table tat drop r1;").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("select * from tat;");
|
|
}).then([&e] (shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().with_rows({
|
|
{ int32_type->decompose(1), int32_type->decompose(2), int32_type->decompose(3), int32_type->decompose(6), from_hex("1234567812345678") },
|
|
});
|
|
return e.execute_cql("alter table tat add r1 int;").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("select * from tat;");
|
|
}).then([&e] (shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().with_rows({
|
|
{ int32_type->decompose(1), int32_type->decompose(2), int32_type->decompose(3), {}, int32_type->decompose(6), from_hex("1234567812345678") },
|
|
});
|
|
return e.execute_cql("alter table tat drop r2;").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("alter table tat add r2 int;").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("select * from tat;");
|
|
}).then([&e] (shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().with_rows({
|
|
{ int32_type->decompose(1), int32_type->decompose(2), int32_type->decompose(3), {}, int32_type->decompose(6), {} },
|
|
});
|
|
});
|
|
});
|
|
}
|
|
|
|
SEASTAR_TEST_CASE(test_map_query) {
|
|
return do_with_cql_env([] (cql_test_env& e) {
|
|
return seastar::async([&e] {
|
|
e.execute_cql("CREATE TABLE xx (k int PRIMARY KEY, m map<text, int>);").get();
|
|
e.execute_cql("insert into xx (k, m) values (0, {'v2': 1});").get();
|
|
auto m_type = map_type_impl::get_instance(utf8_type, int32_type, true);
|
|
assert_that(e.execute_cql("select m from xx where k = 0;").get0())
|
|
.is_rows().with_rows({
|
|
{ make_map_value(m_type, map_type_impl::native_type({{sstring("v2"), 1}})).serialize() }
|
|
});
|
|
e.execute_cql("delete m['v2'] from xx where k = 0;").get();
|
|
assert_that(e.execute_cql("select m from xx where k = 0;").get0())
|
|
.is_rows().with_rows({{{}}});
|
|
});
|
|
});
|
|
}
|
|
|
|
SEASTAR_TEST_CASE(test_drop_table) {
|
|
return do_with_cql_env([] (cql_test_env& e) {
|
|
return seastar::async([&e] {
|
|
e.execute_cql("create table tmp (pk int, v int, PRIMARY KEY (pk));").get();
|
|
e.execute_cql("drop columnfamily tmp;").get();
|
|
e.execute_cql("create table tmp (pk int, v int, PRIMARY KEY (pk));").get();
|
|
e.execute_cql("drop columnfamily tmp;").get();
|
|
});
|
|
});
|
|
}
|
|
|
|
SEASTAR_TEST_CASE(test_reversed_slice_with_empty_range_before_all_rows) {
|
|
return do_with_cql_env([] (cql_test_env& e) {
|
|
return seastar::async([&e] {
|
|
e.execute_cql("CREATE TABLE test (a int, b int, c int, s1 int static, s2 int static, PRIMARY KEY (a, b));").get();
|
|
|
|
e.execute_cql("INSERT INTO test (a, b, c, s1, s2) VALUES (99, 0, 0, 17, 42);").get();
|
|
e.execute_cql("INSERT INTO test (a, b, c, s1, s2) VALUES (99, 1, 1, 17, 42);").get();
|
|
e.execute_cql("INSERT INTO test (a, b, c, s1, s2) VALUES (99, 2, 2, 17, 42);").get();
|
|
e.execute_cql("INSERT INTO test (a, b, c, s1, s2) VALUES (99, 3, 3, 17, 42);").get();
|
|
e.execute_cql("INSERT INTO test (a, b, c, s1, s2) VALUES (99, 4, 4, 17, 42);").get();
|
|
e.execute_cql("INSERT INTO test (a, b, c, s1, s2) VALUES (99, 5, 5, 17, 42);").get();
|
|
e.execute_cql("INSERT INTO test (a, b, c, s1, s2) VALUES (99, 6, 6, 17, 42);").get();
|
|
e.execute_cql("INSERT INTO test (a, b, c, s1, s2) VALUES (99, 7, 7, 17, 42);").get();
|
|
e.execute_cql("INSERT INTO test (a, b, c, s1, s2) VALUES (99, 8, 8, 17, 42);").get();
|
|
e.execute_cql("INSERT INTO test (a, b, c, s1, s2) VALUES (99, 9, 9, 17, 42);").get();
|
|
e.execute_cql("INSERT INTO test (a, b, c, s1, s2) VALUES (99, 10, 10, 17, 42);").get();
|
|
e.execute_cql("INSERT INTO test (a, b, c, s1, s2) VALUES (99, 11, 11, 17, 42);").get();
|
|
e.execute_cql("INSERT INTO test (a, b, c, s1, s2) VALUES (99, 12, 12, 17, 42);").get();
|
|
e.execute_cql("INSERT INTO test (a, b, c, s1, s2) VALUES (99, 13, 13, 17, 42);").get();
|
|
e.execute_cql("INSERT INTO test (a, b, c, s1, s2) VALUES (99, 14, 14, 17, 42);").get();
|
|
e.execute_cql("INSERT INTO test (a, b, c, s1, s2) VALUES (99, 15, 15, 17, 42);").get();
|
|
|
|
assert_that(e.execute_cql("select * from test WHERE a = 99 and b < 0 ORDER BY b DESC limit 2;").get0())
|
|
.is_rows().is_empty();
|
|
|
|
assert_that(e.execute_cql("select * from test WHERE a = 99 order by b desc;").get0())
|
|
.is_rows().with_size(16);
|
|
|
|
assert_that(e.execute_cql("select * from test;").get0())
|
|
.is_rows().with_size(16);
|
|
});
|
|
});
|
|
}
|
|
|
|
SEASTAR_TEST_CASE(test_query_with_range_tombstones) {
|
|
return do_with_cql_env([] (cql_test_env& e) {
|
|
return seastar::async([&e] {
|
|
e.execute_cql("CREATE TABLE test (pk int, ck int, v int, PRIMARY KEY (pk, ck));").get();
|
|
|
|
e.execute_cql("INSERT INTO test (pk, ck, v) VALUES (0, 0, 0);").get();
|
|
e.execute_cql("INSERT INTO test (pk, ck, v) VALUES (0, 2, 2);").get();
|
|
e.execute_cql("INSERT INTO test (pk, ck, v) VALUES (0, 4, 4);").get();
|
|
e.execute_cql("INSERT INTO test (pk, ck, v) VALUES (0, 5, 5);").get();
|
|
e.execute_cql("INSERT INTO test (pk, ck, v) VALUES (0, 6, 6);").get();
|
|
|
|
e.execute_cql("DELETE FROM test WHERE pk = 0 AND ck >= 1 AND ck <= 3;").get();
|
|
e.execute_cql("DELETE FROM test WHERE pk = 0 AND ck > 4 AND ck <= 8;").get();
|
|
e.execute_cql("DELETE FROM test WHERE pk = 0 AND ck > 0 AND ck <= 1;").get();
|
|
|
|
assert_that(e.execute_cql("SELECT v FROM test WHERE pk = 0 ORDER BY ck DESC;").get0())
|
|
.is_rows()
|
|
.with_rows({
|
|
{ int32_type->decompose(4) },
|
|
{ int32_type->decompose(0) },
|
|
});
|
|
|
|
assert_that(e.execute_cql("SELECT v FROM test WHERE pk = 0;").get0())
|
|
.is_rows()
|
|
.with_rows({
|
|
{ int32_type->decompose(0) },
|
|
{ int32_type->decompose(4) },
|
|
});
|
|
});
|
|
});
|
|
}
|
|
|
|
SEASTAR_TEST_CASE(test_alter_table_validation) {
|
|
return do_with_cql_env([] (cql_test_env& e) {
|
|
return e.execute_cql("create table tatv (p1 int, c1 int, c2 int, r1 int, r2 set<int>, PRIMARY KEY (p1, c1, c2));").discard_result().then_wrapped([&e] (future<> f) {
|
|
assert(!f.failed());
|
|
return e.execute_cql("alter table tatv drop r2;").discard_result();
|
|
}).then_wrapped([&e] (future<> f) {
|
|
assert(!f.failed());
|
|
return e.execute_cql("alter table tatv add r2 list<int>;").discard_result();
|
|
}).then_wrapped([&e] (future<> f) {
|
|
assert_that_failed(f);
|
|
return e.execute_cql("alter table tatv add r2 set<text>;").discard_result();
|
|
}).then_wrapped([&e] (future<> f) {
|
|
assert_that_failed(f);
|
|
return e.execute_cql("alter table tatv add r2 set<int>;").discard_result();
|
|
}).then_wrapped([&e] (future<> f) {
|
|
assert(!f.failed());
|
|
return e.execute_cql("alter table tatv rename r2 to r3;").discard_result();
|
|
}).then_wrapped([&e] (future<> f) {
|
|
assert_that_failed(f);
|
|
return e.execute_cql("alter table tatv alter r1 type bigint;").discard_result();
|
|
}).then_wrapped([&e] (future<> f) {
|
|
assert_that_failed(f);
|
|
return e.execute_cql("alter table tatv alter r2 type map<int, int>;").discard_result();
|
|
}).then_wrapped([&e] (future<> f) {
|
|
assert_that_failed(f);
|
|
return e.execute_cql("alter table tatv add r3 map<int, int>;").discard_result();
|
|
}).then_wrapped([&e] (future<> f) {
|
|
assert(!f.failed());
|
|
return e.execute_cql("alter table tatv add r4 set<text>;").discard_result();
|
|
}).then_wrapped([&e] (future<> f) {
|
|
assert(!f.failed());
|
|
return e.execute_cql("alter table tatv drop r3;").discard_result();
|
|
}).then_wrapped([&e] (future<> f) {
|
|
assert(!f.failed());
|
|
return e.execute_cql("alter table tatv drop r4;").discard_result();
|
|
}).then_wrapped([&e] (future<> f) {
|
|
assert(!f.failed());
|
|
return e.execute_cql("alter table tatv add r3 map<int, text>;").discard_result();
|
|
}).then_wrapped([&e] (future<> f) {
|
|
assert_that_failed(f);
|
|
return e.execute_cql("alter table tatv add r4 set<int>;").discard_result();
|
|
}).then_wrapped([&e] (future<> f) {
|
|
assert_that_failed(f);
|
|
return e.execute_cql("alter table tatv add r3 map<int, blob>;").discard_result();
|
|
}).then_wrapped([&e] (future<> f) {
|
|
assert(!f.failed());
|
|
return e.execute_cql("alter table tatv add r4 set<blob>;").discard_result();
|
|
}).then_wrapped([&e] (future<> f) {
|
|
assert(!f.failed());
|
|
});
|
|
});
|
|
}
|
|
|
|
SEASTAR_TEST_CASE(test_pg_style_string_literal) {
|
|
return do_with_cql_env([] (cql_test_env& e) {
|
|
return e.execute_cql("create table test (p1 text, PRIMARY KEY (p1));").discard_result().then([&e] {
|
|
return e.execute_cql("insert into test (p1) values ($$Apostrophe's$ $ not$ $ '' escaped$$);").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("insert into test (p1) values ($$$''valid$_$key$$);").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("insert into test (p1) values ('$normal$valid$$$$key$');").discard_result();
|
|
}).then([&e] {
|
|
return e.execute_cql("insert into test (p1) values ($ $invalid$$);").discard_result();
|
|
}).then_wrapped([&e] (future<> f) {
|
|
assert_that_failed(f);
|
|
return e.execute_cql("insert into test (p1) values ($$invalid$ $);").discard_result();
|
|
}).then_wrapped([&e] (future<> f) {
|
|
assert_that_failed(f);
|
|
return e.execute_cql("insert into test (p1) values ($ $invalid$$$);").discard_result();
|
|
}).then_wrapped([&e] (future<> f) {
|
|
assert_that_failed(f);
|
|
return e.execute_cql("insert into test (p1) values ($$ \n\n$invalid);").discard_result();
|
|
}).then_wrapped([&e] (future<> f) {
|
|
assert_that_failed(f);
|
|
return e.execute_cql("select * from test;");
|
|
}).then([&e] (shared_ptr<cql_transport::messages::result_message> msg) {
|
|
assert_that(msg).is_rows().with_rows({
|
|
{ utf8_type->decompose(sstring("Apostrophe's$ $ not$ $ '' escaped")) },
|
|
{ utf8_type->decompose(sstring("$''valid$_$key")) },
|
|
{ utf8_type->decompose(sstring("$normal$valid$$$$key$")) },
|
|
});
|
|
});
|
|
});
|
|
}
|
|
|
|
SEASTAR_TEST_CASE(test_insert_large_collection_values) {
|
|
return do_with_cql_env([] (cql_test_env& e) {
|
|
return seastar::async([&e] {
|
|
auto map_type = map_type_impl::get_instance(utf8_type, utf8_type, true);
|
|
auto set_type = set_type_impl::get_instance(utf8_type, true);
|
|
auto list_type = list_type_impl::get_instance(utf8_type, true);
|
|
e.create_table([map_type, set_type, list_type] (sstring ks_name) {
|
|
// CQL: CREATE TABLE tbl (pk text PRIMARY KEY, m map<text, text>, s set<text>, l list<text>);
|
|
return schema({}, ks_name, "tbl",
|
|
{{"pk", utf8_type}},
|
|
{},
|
|
{
|
|
{"m", map_type},
|
|
{"s", set_type},
|
|
{"l", list_type}
|
|
},
|
|
{},
|
|
utf8_type);
|
|
}).get();
|
|
sstring long_value(std::numeric_limits<uint16_t>::max() + 10, 'x');
|
|
e.execute_cql(format("INSERT INTO tbl (pk, l) VALUES ('Zamyatin', ['{}']);", long_value)).get();
|
|
assert_that(e.execute_cql("SELECT l FROM tbl WHERE pk ='Zamyatin';").get0())
|
|
.is_rows().with_rows({
|
|
{ make_list_value(list_type, list_type_impl::native_type({{long_value}})).serialize() }
|
|
});
|
|
BOOST_REQUIRE_THROW(e.execute_cql(format("INSERT INTO tbl (pk, s) VALUES ('Orwell', {{'{}'}});", long_value)).get(), std::exception);
|
|
e.execute_cql(format("INSERT INTO tbl (pk, m) VALUES ('Haksli', {{'key': '{}'}});", long_value)).get();
|
|
assert_that(e.execute_cql("SELECT m FROM tbl WHERE pk ='Haksli';").get0())
|
|
.is_rows().with_rows({
|
|
{ make_map_value(map_type, map_type_impl::native_type({{sstring("key"), long_value}})).serialize() }
|
|
});
|
|
BOOST_REQUIRE_THROW(e.execute_cql(format("INSERT INTO tbl (pk, m) VALUES ('Golding', {{'{}': 'value'}});", long_value)).get(), std::exception);
|
|
|
|
auto make_query_options = [] (cql_protocol_version_type version) {
|
|
return std::make_unique<cql3::query_options>(db::consistency_level::ONE, infinite_timeout_config, std::experimental::nullopt,
|
|
std::vector<cql3::raw_value_view>(), false,
|
|
cql3::query_options::specific_options::DEFAULT, cql_serialization_format{version});
|
|
};
|
|
|
|
BOOST_REQUIRE_THROW(e.execute_cql("SELECT l FROM tbl WHERE pk = 'Zamyatin';", make_query_options(2)).get(), std::exception);
|
|
BOOST_REQUIRE_THROW(e.execute_cql("SELECT m FROM tbl WHERE pk = 'Haksli';", make_query_options(2)).get(), std::exception);
|
|
});
|
|
});
|
|
}
|
|
|
|
SEASTAR_TEST_CASE(test_long_text_value) {
|
|
return do_with_cql_env_thread([] (cql_test_env& e) {
|
|
auto prepared = e.execute_cql("CREATE TABLE t (id int PRIMARY KEY, v text, v2 varchar)").get();
|
|
e.require_table_exists("ks", "t").get();
|
|
sstring big_one(17324, 'x');
|
|
sstring bigger_one(29123, 'y');
|
|
e.execute_cql(format("INSERT INTO t (id, v, v2) values (1, '{}', '{}')", big_one, big_one)).get();
|
|
e.execute_cql(format("INSERT INTO t (id, v, v2) values (2, '{}', '{}')", bigger_one, bigger_one)).get();
|
|
auto msg = e.execute_cql("select v, v2 from t where id = 1").get0();
|
|
assert_that(msg).is_rows().with_rows({{utf8_type->decompose(big_one), utf8_type->decompose(big_one)}});
|
|
msg = e.execute_cql("select v, v2 from t where id = 2").get0();
|
|
assert_that(msg).is_rows().with_rows({{utf8_type->decompose(bigger_one), utf8_type->decompose(bigger_one)}});
|
|
});
|
|
}
|
|
|
|
SEASTAR_TEST_CASE(test_time_conversions) {
|
|
return do_with_cql_env_thread([] (cql_test_env& e) {
|
|
auto prepared = e.execute_cql(
|
|
"CREATE TABLE time_data (id timeuuid PRIMARY KEY, d date, ts timestamp);").get();
|
|
e.require_table_exists("ks", "time_data").get();
|
|
|
|
e.execute_cql("INSERT INTO time_data (id, d, ts) VALUES (f4e30f80-6958-11e8-96d6-000000000000, '2017-06-11', '2018-06-05 00:00:00+0000');").get();
|
|
|
|
struct tm t = { 0 };
|
|
t.tm_year = 2018 - 1900;
|
|
t.tm_mon = 6 - 1;
|
|
t.tm_mday = 6;
|
|
t.tm_hour = 7;
|
|
t.tm_min = 12;
|
|
t.tm_sec = 22;
|
|
auto tp1 = db_clock::from_time_t(timegm(&t)) + std::chrono::milliseconds(136);
|
|
t.tm_year = 2017 - 1900;
|
|
t.tm_mday = 11;
|
|
t.tm_hour = 0;
|
|
t.tm_min = 0;
|
|
t.tm_sec = 0;
|
|
auto tp2 = db_clock::from_time_t(timegm(&t));
|
|
|
|
auto msg = e.execute_cql("select todate(id), todate(ts), totimestamp(id), totimestamp(d), tounixtimestamp(id),"
|
|
"tounixtimestamp(ts), tounixtimestamp(d), tounixtimestamp(totimestamp(todate(totimestamp(todate(id))))) from time_data;").get0();
|
|
assert_that(msg).is_rows().with_rows({{
|
|
simple_date_type->decompose(int32_t(0x80004518)),
|
|
simple_date_type->decompose(int32_t(0x80004517)),
|
|
timestamp_type->decompose(tp1),
|
|
timestamp_type->decompose(tp2),
|
|
long_type->decompose(int64_t(1528269142136)),
|
|
long_type->decompose(int64_t(1528156800000)),
|
|
long_type->decompose(int64_t(1497139200000)),
|
|
long_type->decompose(int64_t(1528243200000))
|
|
}});
|
|
|
|
});
|
|
}
|
|
|
|
// Corner-case test that checks for the paging code's preparedness for an empty
|
|
// range list.
|
|
SEASTAR_TEST_CASE(test_empty_partition_range_scan) {
|
|
return do_with_cql_env_thread([] (cql_test_env& e) {
|
|
e.execute_cql("create keyspace empty_partition_range_scan with replication = {'class': 'SimpleStrategy', 'replication_factor': 1};").get();
|
|
e.execute_cql("create table empty_partition_range_scan.tb (a int, b int, c int, val int, PRIMARY KEY ((a,b),c) );").get();
|
|
|
|
|
|
auto qo = std::make_unique<cql3::query_options>(db::consistency_level::LOCAL_ONE, infinite_timeout_config, std::vector<cql3::raw_value>{},
|
|
cql3::query_options::specific_options{1, nullptr, {}, api::new_timestamp()});
|
|
auto res = e.execute_cql("select * from empty_partition_range_scan.tb where token (a,b) > 1 and token(a,b) <= 1;", std::move(qo)).get0();
|
|
assert_that(res).is_rows().is_empty();
|
|
});
|
|
}
|
|
|
|
SEASTAR_TEST_CASE(test_allow_filtering_check) {
|
|
return do_with_cql_env_thread([] (cql_test_env& e) {
|
|
e.execute_cql("CREATE TABLE t (p int, c int, v int, PRIMARY KEY(p, c));").get();
|
|
e.require_table_exists("ks", "t").get();
|
|
|
|
for (int i = 0; i < 3; ++i) {
|
|
for (int j = 0; j <3; ++j) {
|
|
e.execute_cql(format("INSERT INTO t(p, c, v) VALUES ({}, {}, {})", i, j, j)).get();
|
|
}
|
|
}
|
|
|
|
std::vector<sstring> queries = {
|
|
"SELECT * FROM t WHERE p = 1",
|
|
"SELECT * FROM t WHERE p = 1 and c > 2",
|
|
"SELECT * FROM t WHERE p = 1 and c = 2"
|
|
};
|
|
|
|
for (const sstring& q : queries) {
|
|
e.execute_cql(q).get();
|
|
e.execute_cql(q + " ALLOW FILTERING").get();
|
|
}
|
|
|
|
queries = {
|
|
"SELECT * FROM t WHERE c = 2",
|
|
"SELECT * FROM t WHERE c <= 4"
|
|
};
|
|
|
|
for (const sstring& q : queries) {
|
|
BOOST_CHECK_THROW(e.execute_cql(q).get(), exceptions::invalid_request_exception);
|
|
e.execute_cql(q + " ALLOW FILTERING").get();
|
|
}
|
|
|
|
e.execute_cql("CREATE TABLE t2 (p int PRIMARY KEY, a int, b int);").get();
|
|
e.require_table_exists("ks", "t2").get();
|
|
e.execute_cql("CREATE INDEX ON t2(a)").get();
|
|
for (int i = 0; i < 5; ++i) {
|
|
e.execute_cql(format("INSERT INTO t2 (p, a, b) VALUES ({}, {}, {})", i, i * 10, i * 100)).get();
|
|
}
|
|
|
|
queries = {
|
|
"SELECT * FROM t2 WHERE p = 1",
|
|
"SELECT * FROM t2 WHERE a = 20"
|
|
};
|
|
|
|
for (const sstring& q : queries) {
|
|
e.execute_cql(q).get();
|
|
e.execute_cql(q + " ALLOW FILTERING").get();
|
|
}
|
|
|
|
queries = {
|
|
"SELECT * FROM t2 WHERE a = 20 AND b = 200"
|
|
};
|
|
|
|
for (const sstring& q : queries) {
|
|
BOOST_CHECK_THROW(e.execute_cql(q).get(), exceptions::invalid_request_exception);
|
|
e.execute_cql(q + " ALLOW FILTERING").get();
|
|
}
|
|
});
|
|
}
|
|
|
|
SEASTAR_TEST_CASE(test_allow_filtering_pk_ck) {
|
|
return do_with_cql_env_thread([] (cql_test_env& e) {
|
|
e.execute_cql("CREATE TABLE t (a int, b int, c int, d int, e int, PRIMARY KEY ((a, b), c, d));").get();
|
|
e.require_table_exists("ks", "t").get();
|
|
e.execute_cql("INSERT INTO t (a,b,c,d,e) VALUES (11, 12, 13, 14, 15)").get();
|
|
e.execute_cql("INSERT INTO t (a,b,c,d,e) VALUES (11, 15, 16, 17, 18)").get();
|
|
e.execute_cql("INSERT INTO t (a,b,c,d,e) VALUES (21, 22, 23, 24, 25)").get();
|
|
e.execute_cql("INSERT INTO t (a,b,c,d,e) VALUES (31, 32, 33, 34, 35)").get();
|
|
|
|
auto msg = e.execute_cql("SELECT * FROM t WHERE a = 11 AND b = 15 AND c = 16").get0();
|
|
assert_that(msg).is_rows().with_rows({{
|
|
int32_type->decompose(11),
|
|
int32_type->decompose(15),
|
|
int32_type->decompose(16),
|
|
int32_type->decompose(17),
|
|
int32_type->decompose(18),
|
|
}});
|
|
|
|
BOOST_CHECK_THROW(e.execute_cql("SELECT * FROM t WHERE a = 11 AND b = 12 AND c > 13 AND d = 14").get(), exceptions::invalid_request_exception);
|
|
|
|
msg = e.execute_cql("SELECT * FROM t WHERE a = 11 AND b = 15 AND c = 16").get0();
|
|
assert_that(msg).is_rows().with_rows({{
|
|
int32_type->decompose(11),
|
|
int32_type->decompose(15),
|
|
int32_type->decompose(16),
|
|
int32_type->decompose(17),
|
|
int32_type->decompose(18),
|
|
}});
|
|
|
|
msg = e.execute_cql("SELECT * FROM t WHERE a = 11 AND b = 15 AND c > 13 AND d >= 17 ALLOW FILTERING").get0();
|
|
assert_that(msg).is_rows().with_rows({{
|
|
int32_type->decompose(11),
|
|
int32_type->decompose(15),
|
|
int32_type->decompose(16),
|
|
int32_type->decompose(17),
|
|
int32_type->decompose(18),
|
|
}});
|
|
|
|
BOOST_CHECK_THROW(e.execute_cql("SELECT * FROM t WHERE a = 11 AND b = 12 AND c > 13 AND d > 17").get(), exceptions::invalid_request_exception);
|
|
|
|
msg = e.execute_cql("SELECT * FROM t WHERE a = 11 AND b = 15 AND c > 13 AND d >= 17 ALLOW FILTERING").get0();
|
|
assert_that(msg).is_rows().with_rows({{
|
|
int32_type->decompose(11),
|
|
int32_type->decompose(15),
|
|
int32_type->decompose(16),
|
|
int32_type->decompose(17),
|
|
int32_type->decompose(18),
|
|
}});
|
|
|
|
msg = e.execute_cql("SELECT * FROM t WHERE a <= 11 AND c > 15 AND d >= 16 ALLOW FILTERING").get0();
|
|
assert_that(msg).is_rows().with_rows({{
|
|
int32_type->decompose(11),
|
|
int32_type->decompose(15),
|
|
int32_type->decompose(16),
|
|
int32_type->decompose(17),
|
|
int32_type->decompose(18),
|
|
}});
|
|
|
|
msg = e.execute_cql("SELECT * FROM t WHERE a <= 11 AND b >= 15 AND c > 15 AND d >= 16 ALLOW FILTERING").get0();
|
|
assert_that(msg).is_rows().with_rows({{
|
|
int32_type->decompose(11),
|
|
int32_type->decompose(15),
|
|
int32_type->decompose(16),
|
|
int32_type->decompose(17),
|
|
int32_type->decompose(18),
|
|
}});
|
|
|
|
msg = e.execute_cql("SELECT * FROM t WHERE a <= 100 AND b >= 15 AND c > 0 AND d <= 100 ALLOW FILTERING").get0();
|
|
assert_that(msg).is_rows().with_rows({
|
|
{
|
|
int32_type->decompose(11),
|
|
int32_type->decompose(15),
|
|
int32_type->decompose(16),
|
|
int32_type->decompose(17),
|
|
int32_type->decompose(18),
|
|
},
|
|
{
|
|
int32_type->decompose(31),
|
|
int32_type->decompose(32),
|
|
int32_type->decompose(33),
|
|
int32_type->decompose(34),
|
|
int32_type->decompose(35),
|
|
},
|
|
{
|
|
int32_type->decompose(21),
|
|
int32_type->decompose(22),
|
|
int32_type->decompose(23),
|
|
int32_type->decompose(24),
|
|
int32_type->decompose(25),
|
|
}
|
|
});
|
|
|
|
BOOST_CHECK_THROW(e.execute_cql("SELECT * FROM t WHERE a <= 11 AND c > 15 AND d >= 16").get(), exceptions::invalid_request_exception);
|
|
});
|
|
}
|
|
|
|
SEASTAR_TEST_CASE(test_allow_filtering_clustering_column) {
|
|
return do_with_cql_env_thread([] (cql_test_env& e) {
|
|
e.execute_cql("CREATE TABLE t (k int, c int, v int, PRIMARY KEY (k, c));").get();
|
|
e.require_table_exists("ks", "t").get();
|
|
|
|
e.execute_cql("INSERT INTO t (k, c, v) VALUES (1, 2, 1)").get();
|
|
e.execute_cql("INSERT INTO t (k, c, v) VALUES (1, 3, 2)").get();
|
|
e.execute_cql("INSERT INTO t (k, c, v) VALUES (2, 2, 3)").get();
|
|
|
|
auto msg = e.execute_cql("SELECT * FROM t WHERE k = 1").get0();
|
|
assert_that(msg).is_rows().with_rows({
|
|
{
|
|
int32_type->decompose(1),
|
|
int32_type->decompose(2),
|
|
int32_type->decompose(1)
|
|
},
|
|
{
|
|
int32_type->decompose(1),
|
|
int32_type->decompose(3),
|
|
int32_type->decompose(2)
|
|
}
|
|
});
|
|
|
|
msg = e.execute_cql("SELECT * FROM t WHERE k = 1 AND c > 2").get0();
|
|
assert_that(msg).is_rows().with_rows({{
|
|
int32_type->decompose(1),
|
|
int32_type->decompose(3),
|
|
int32_type->decompose(2)
|
|
}});
|
|
|
|
msg = e.execute_cql("SELECT * FROM t WHERE k = 1 AND c = 2").get0();
|
|
assert_that(msg).is_rows().with_rows({{
|
|
int32_type->decompose(1),
|
|
int32_type->decompose(2),
|
|
int32_type->decompose(1)
|
|
}});
|
|
|
|
BOOST_CHECK_THROW(e.execute_cql("SELECT * FROM t WHERE c = 2").get(), exceptions::invalid_request_exception);
|
|
BOOST_CHECK_THROW(e.execute_cql("SELECT * FROM t WHERE c > 2 AND c <= 4").get(), exceptions::invalid_request_exception);
|
|
|
|
msg = e.execute_cql("SELECT * FROM t WHERE c = 2 ALLOW FILTERING").get0();
|
|
assert_that(msg).is_rows().with_rows({
|
|
{
|
|
int32_type->decompose(1),
|
|
int32_type->decompose(2),
|
|
int32_type->decompose(1)
|
|
},
|
|
{
|
|
int32_type->decompose(2),
|
|
int32_type->decompose(2),
|
|
int32_type->decompose(3)
|
|
}
|
|
});
|
|
|
|
msg = e.execute_cql("SELECT * FROM t WHERE c > 2 AND c <= 4 ALLOW FILTERING").get0();
|
|
assert_that(msg).is_rows().with_rows({{
|
|
int32_type->decompose(1),
|
|
int32_type->decompose(3),
|
|
int32_type->decompose(2)
|
|
}});
|
|
});
|
|
}
|
|
|
|
SEASTAR_TEST_CASE(test_allow_filtering_static_column) {
|
|
return do_with_cql_env_thread([] (cql_test_env& e) {
|
|
e.execute_cql("CREATE TABLE t (a int, b int, c int, s int static, PRIMARY KEY(a, b));").get();
|
|
e.require_table_exists("ks", "t").get();
|
|
e.execute_cql("CREATE INDEX ON t(c)").get();
|
|
|
|
e.execute_cql("INSERT INTO t (a, b, c, s) VALUES (1, 1, 1, 1)").get();
|
|
e.execute_cql("INSERT INTO t (a, b, c) VALUES (1, 2, 1)").get();
|
|
e.execute_cql("INSERT INTO t (a, s) VALUES (3, 3)").get();
|
|
e.execute_cql("INSERT INTO t (a, b, c, s) VALUES (2, 1, 1, 2)").get();
|
|
|
|
eventually([&] {
|
|
auto msg = e.execute_cql("SELECT * FROM t WHERE c = 1 AND s = 2 ALLOW FILTERING").get0();
|
|
assert_that(msg).is_rows().with_rows({{
|
|
int32_type->decompose(2),
|
|
int32_type->decompose(1),
|
|
int32_type->decompose(2),
|
|
int32_type->decompose(1)
|
|
}});
|
|
});
|
|
|
|
eventually([&] {
|
|
auto msg = e.execute_cql("SELECT * FROM t WHERE c = 1 AND s = 1 ALLOW FILTERING").get0();
|
|
assert_that(msg).is_rows().with_rows({
|
|
{
|
|
int32_type->decompose(1),
|
|
int32_type->decompose(1),
|
|
int32_type->decompose(1),
|
|
int32_type->decompose(1)
|
|
},
|
|
{
|
|
int32_type->decompose(1),
|
|
int32_type->decompose(2),
|
|
int32_type->decompose(1),
|
|
int32_type->decompose(1)
|
|
}
|
|
});
|
|
});
|
|
});
|
|
}
|
|
|
|
SEASTAR_TEST_CASE(test_allow_filtering_multiple_regular) {
|
|
return do_with_cql_env_thread([] (cql_test_env& e) {
|
|
e.execute_cql("CREATE TABLE t (a int, b int, c int, d int, e int, f list<int>, g set<int>, PRIMARY KEY(a, b));").get();
|
|
e.require_table_exists("ks", "t").get();
|
|
|
|
e.execute_cql("INSERT INTO t (a, b, c, d, e, f, g) VALUES (1, 1, 1, 1, 1, [1], {})").get();
|
|
e.execute_cql("INSERT INTO t (a, b, c, d, e, f, g) VALUES (1, 2, 3, 4, 5, [1, 2], {1, 2, 3})").get();
|
|
e.execute_cql("INSERT INTO t (a, b, c, d, e, f, g) VALUES (1, 3, 5, 1, 9, [1, 2, 3], {1, 2})").get();
|
|
e.execute_cql("INSERT INTO t (a, b, c, d, e, f, g) VALUES (1, 4, 5, 7, 5, [], {1})").get();
|
|
|
|
BOOST_CHECK_THROW(e.execute_cql("SELECT * FROM t WHERE c = 5").get(), exceptions::invalid_request_exception);
|
|
BOOST_CHECK_THROW(e.execute_cql("SELECT * FROM t WHERE d = 1").get(), exceptions::invalid_request_exception);
|
|
BOOST_CHECK_THROW(e.execute_cql("SELECT * FROM t WHERE e = 5").get(), exceptions::invalid_request_exception);
|
|
|
|
// Collection filtering queries are not supported yet
|
|
BOOST_CHECK_THROW(e.execute_cql("SELECT * FROM t WHERE f contains 2").get(), exceptions::invalid_request_exception);
|
|
BOOST_CHECK_THROW(e.execute_cql("SELECT * FROM t WHERE g contains 1").get(), exceptions::invalid_request_exception);
|
|
|
|
auto msg = e.execute_cql("SELECT a, b, c, d, e FROM t WHERE c = 3 ALLOW FILTERING").get0();
|
|
assert_that(msg).is_rows().with_rows({{
|
|
int32_type->decompose(1),
|
|
int32_type->decompose(2),
|
|
int32_type->decompose(3),
|
|
int32_type->decompose(4),
|
|
int32_type->decompose(5)
|
|
}});
|
|
|
|
msg = e.execute_cql("SELECT a, b, c, d, e FROM t WHERE e >= 5 ALLOW FILTERING").get0();
|
|
assert_that(msg).is_rows().with_rows({
|
|
{
|
|
int32_type->decompose(1),
|
|
int32_type->decompose(2),
|
|
int32_type->decompose(3),
|
|
int32_type->decompose(4),
|
|
int32_type->decompose(5)
|
|
},
|
|
{
|
|
int32_type->decompose(1),
|
|
int32_type->decompose(3),
|
|
int32_type->decompose(5),
|
|
int32_type->decompose(1),
|
|
int32_type->decompose(9)
|
|
},
|
|
{
|
|
int32_type->decompose(1),
|
|
int32_type->decompose(4),
|
|
int32_type->decompose(5),
|
|
int32_type->decompose(7),
|
|
int32_type->decompose(5)
|
|
}
|
|
});
|
|
|
|
msg = e.execute_cql("SELECT a, b, c, d, e FROM t WHERE c = 5 and e = 9 and d = 1 ALLOW FILTERING").get0();
|
|
assert_that(msg).is_rows().with_rows({{
|
|
int32_type->decompose(1),
|
|
int32_type->decompose(3),
|
|
int32_type->decompose(5),
|
|
int32_type->decompose(1),
|
|
int32_type->decompose(9)
|
|
}});
|
|
|
|
cql3::prepared_cache_key_type prepared_id = e.prepare("SELECT a, b, c, d, e FROM t WHERE a = ? and d = ? ALLOW FILTERING").get0();
|
|
std::vector<cql3::raw_value> raw_values {
|
|
cql3::raw_value::make_value(int32_type->decompose(1)),
|
|
cql3::raw_value::make_value(int32_type->decompose(1))
|
|
};
|
|
msg = e.execute_prepared(prepared_id, raw_values).get0();
|
|
assert_that(msg).is_rows().with_rows({
|
|
{
|
|
int32_type->decompose(1),
|
|
int32_type->decompose(1),
|
|
int32_type->decompose(1),
|
|
int32_type->decompose(1),
|
|
int32_type->decompose(1)
|
|
},
|
|
{
|
|
int32_type->decompose(1),
|
|
int32_type->decompose(3),
|
|
int32_type->decompose(5),
|
|
int32_type->decompose(1),
|
|
int32_type->decompose(9)
|
|
}
|
|
});
|
|
|
|
prepared_id = e.prepare("SELECT a, b, c, d, e FROM t WHERE a = ? and d = ? ALLOW FILTERING").get0();
|
|
raw_values[1] = cql3::raw_value::make_value(int32_type->decompose(9));
|
|
msg = e.execute_prepared(prepared_id, raw_values).get0();
|
|
assert_that(msg).is_rows().with_size(0);
|
|
|
|
|
|
});
|
|
}
|
|
|
|
SEASTAR_TEST_CASE(test_allow_filtering_desc) {
|
|
return do_with_cql_env_thread([] (cql_test_env& e) {
|
|
e.execute_cql("CREATE TABLE t (a int, b int, c int, d int, e int, PRIMARY KEY((a, b), c, d)) WITH CLUSTERING ORDER BY (c DESC);").get();
|
|
e.require_table_exists("ks", "t").get();
|
|
|
|
e.execute_cql("INSERT INTO t (a, b, c, d, e) VALUES (1, 2, 1, 1, 1)").get();
|
|
e.execute_cql("INSERT INTO t (a, b, c, d, e) VALUES (1, 2, 3, 4, 5)").get();
|
|
e.execute_cql("INSERT INTO t (a, b, c, d, e) VALUES (1, 2, 5, 1, 9)").get();
|
|
e.execute_cql("INSERT INTO t (a, b, c, d, e) VALUES (1, 2, 6, 7, 5)").get();
|
|
|
|
auto msg = e.execute_cql("SELECT a, b, c, d, e FROM t WHERE c > 3 ALLOW FILTERING").get0();
|
|
assert_that(msg).is_rows().with_rows({
|
|
{
|
|
int32_type->decompose(1),
|
|
int32_type->decompose(2),
|
|
int32_type->decompose(6),
|
|
int32_type->decompose(7),
|
|
int32_type->decompose(5)
|
|
},
|
|
{
|
|
int32_type->decompose(1),
|
|
int32_type->decompose(2),
|
|
int32_type->decompose(5),
|
|
int32_type->decompose(1),
|
|
int32_type->decompose(9)
|
|
}
|
|
});
|
|
|
|
msg = e.execute_cql("SELECT a, b, c, d, e FROM t WHERE c < 4 ALLOW FILTERING").get0();
|
|
assert_that(msg).is_rows().with_rows({
|
|
{
|
|
int32_type->decompose(1),
|
|
int32_type->decompose(2),
|
|
int32_type->decompose(3),
|
|
int32_type->decompose(4),
|
|
int32_type->decompose(5)
|
|
},
|
|
{
|
|
int32_type->decompose(1),
|
|
int32_type->decompose(2),
|
|
int32_type->decompose(1),
|
|
int32_type->decompose(1),
|
|
int32_type->decompose(1)
|
|
}
|
|
});
|
|
|
|
msg = e.execute_cql("SELECT a, b, c, d, e FROM t WHERE c = 4 ALLOW FILTERING").get0();
|
|
assert_that(msg).is_rows().with_size(0);
|
|
});
|
|
}
|
|
|
|
SEASTAR_TEST_CASE(test_allow_filtering_with_secondary_index) {
|
|
return do_with_cql_env_thread([] (cql_test_env& e) {
|
|
e.execute_cql("CREATE TABLE t (a int, b int, c int, d int, e int, PRIMARY KEY(a, b));").get();
|
|
e.require_table_exists("ks", "t").get();
|
|
e.execute_cql("CREATE INDEX ON t(c)").get();
|
|
|
|
e.execute_cql("INSERT INTO t (a, b, c, d, e) VALUES (1, 1, 1, 1, 1)").get();
|
|
e.execute_cql("INSERT INTO t (a, b, c, d, e) VALUES (1, 2, 3, 4, 5)").get();
|
|
e.execute_cql("INSERT INTO t (a, b, c, d, e) VALUES (1, 3, 5, 1, 9)").get();
|
|
e.execute_cql("INSERT INTO t (a, b, c, d, e) VALUES (1, 4, 5, 7, 5)").get();
|
|
|
|
auto msg = e.execute_cql("SELECT a, b, c, d, e FROM t WHERE c = 3").get0();
|
|
assert_that(msg).is_rows().with_rows({{
|
|
int32_type->decompose(1),
|
|
int32_type->decompose(2),
|
|
int32_type->decompose(3),
|
|
int32_type->decompose(4),
|
|
int32_type->decompose(5)
|
|
}});
|
|
|
|
BOOST_CHECK_THROW(e.execute_cql("SELECT * FROM t WHERE c = 5 and d = 1").get(), exceptions::invalid_request_exception);
|
|
|
|
msg = e.execute_cql("SELECT a, b, c, d, e FROM t WHERE c = 5 and d = 1 ALLOW FILTERING").get0();
|
|
assert_that(msg).is_rows().with_rows({{
|
|
int32_type->decompose(1),
|
|
int32_type->decompose(3),
|
|
int32_type->decompose(5),
|
|
int32_type->decompose(1),
|
|
int32_type->decompose(9)
|
|
}});
|
|
|
|
e.execute_cql("CREATE TABLE t2 (pk1 int, pk2 int, c1 int, c2 int, v int, PRIMARY KEY ((pk1, pk2), c1, c2));").get();
|
|
e.execute_cql("CREATE INDEX ON t2(v)").get();
|
|
for (int i = 1; i <= 5; ++i) {
|
|
for (int j = 1; j <= 2; ++j) {
|
|
e.execute_cql(format("INSERT INTO t2 (pk1, pk2, c1, c2, v) VALUES ({}, {}, {}, {}, {})", j, 1, 1, 1, i)).get();
|
|
e.execute_cql(format("INSERT INTO t2 (pk1, pk2, c1, c2, v) VALUES ({}, {}, {}, {}, {})", j, 1, 1, i, i)).get();
|
|
e.execute_cql(format("INSERT INTO t2 (pk1, pk2, c1, c2, v) VALUES ({}, {}, {}, {}, {})", j, 1, i, i, i)).get();
|
|
e.execute_cql(format("INSERT INTO t2 (pk1, pk2, c1, c2, v) VALUES ({}, {}, {}, {}, {})", j, i, i, i, i)).get();
|
|
}
|
|
}
|
|
|
|
eventually([&] {
|
|
auto msg = e.execute_cql("SELECT * FROM t2 WHERE pk1 = 1 AND c1 > 0 AND c1 < 5 AND c2 = 1 AND v = 3 ALLOW FILTERING;").get0();
|
|
assert_that(msg).is_rows().with_rows({});
|
|
});
|
|
|
|
eventually([&] {
|
|
auto msg = e.execute_cql("SELECT * FROM t2 WHERE pk1 = 1 AND c1 > 0 AND c1 < 5 AND c2 = 3 AND v = 3 ALLOW FILTERING;").get0();
|
|
assert_that(msg).is_rows().with_rows({
|
|
{
|
|
int32_type->decompose(1),
|
|
int32_type->decompose(3),
|
|
int32_type->decompose(3),
|
|
int32_type->decompose(3),
|
|
int32_type->decompose(3)
|
|
},
|
|
{
|
|
int32_type->decompose(1),
|
|
int32_type->decompose(1),
|
|
int32_type->decompose(1),
|
|
int32_type->decompose(3),
|
|
int32_type->decompose(3)
|
|
},
|
|
{
|
|
int32_type->decompose(1),
|
|
int32_type->decompose(1),
|
|
int32_type->decompose(3),
|
|
int32_type->decompose(3),
|
|
int32_type->decompose(3)
|
|
}
|
|
});
|
|
});
|
|
|
|
eventually([&] {
|
|
auto msg = e.execute_cql("SELECT * FROM t2 WHERE pk1 = 1 AND c2 > 1 AND c2 < 5 AND v = 1 ALLOW FILTERING;").get0();
|
|
assert_that(msg).is_rows().with_rows({});
|
|
});
|
|
|
|
eventually([&] {
|
|
auto msg = e.execute_cql("SELECT * FROM t2 WHERE pk1 = 1 AND c1 > 1 AND c2 > 2 AND v = 3 ALLOW FILTERING;").get0();
|
|
assert_that(msg).is_rows().with_rows({
|
|
{
|
|
int32_type->decompose(1),
|
|
int32_type->decompose(3),
|
|
int32_type->decompose(3),
|
|
int32_type->decompose(3),
|
|
int32_type->decompose(3)
|
|
},
|
|
{
|
|
int32_type->decompose(1),
|
|
int32_type->decompose(1),
|
|
int32_type->decompose(3),
|
|
int32_type->decompose(3),
|
|
int32_type->decompose(3)
|
|
}
|
|
});
|
|
});
|
|
|
|
eventually([&] {
|
|
auto msg = e.execute_cql("SELECT * FROM t2 WHERE pk1 = 1 AND pk2 > 1 AND c2 > 2 AND v = 3 ALLOW FILTERING;").get0();
|
|
assert_that(msg).is_rows().with_rows({{
|
|
int32_type->decompose(1),
|
|
int32_type->decompose(3),
|
|
int32_type->decompose(3),
|
|
int32_type->decompose(3),
|
|
int32_type->decompose(3)
|
|
}});
|
|
});
|
|
|
|
eventually([&] {
|
|
auto msg = e.execute_cql("SELECT * FROM t2 WHERE pk1 >= 2 AND pk2 <=3 AND c1 IN(0,1,2) AND c2 IN(0,1,2) AND v < 3 ALLOW FILTERING;").get0();
|
|
assert_that(msg).is_rows().with_rows({
|
|
{
|
|
int32_type->decompose(2),
|
|
int32_type->decompose(2),
|
|
int32_type->decompose(2),
|
|
int32_type->decompose(2),
|
|
int32_type->decompose(2)
|
|
},
|
|
{
|
|
int32_type->decompose(2),
|
|
int32_type->decompose(1),
|
|
int32_type->decompose(1),
|
|
int32_type->decompose(2),
|
|
int32_type->decompose(2)
|
|
},
|
|
{
|
|
int32_type->decompose(2),
|
|
int32_type->decompose(1),
|
|
int32_type->decompose(2),
|
|
int32_type->decompose(2),
|
|
int32_type->decompose(2)
|
|
}
|
|
});
|
|
});
|
|
});
|
|
}
|
|
|
|
SEASTAR_TEST_CASE(test_allow_filtering_contains) {
|
|
return do_with_cql_env_thread([] (cql_test_env& e) {
|
|
e.execute_cql("CREATE TABLE t (p frozen<map<text, text>>, c1 frozen<list<int>>, c2 frozen<set<int>>, v map<text, text>, PRIMARY KEY(p, c1, c2));").get();
|
|
e.require_table_exists("ks", "t").get();
|
|
|
|
e.execute_cql("INSERT INTO t (p, c1, c2, v) VALUES ({'a':'a'}, [1,2,3], {1, 5}, {'x':'xyz', 'y1':'abc'});").get();
|
|
e.execute_cql("INSERT INTO t (p, c1, c2, v) VALUES ({'b':'b'}, [2,3,4], {3, 4}, {'d':'def', 'y1':'abc'});").get();
|
|
e.execute_cql("INSERT INTO t (p, c1, c2, v) VALUES ({'c':'c'}, [3,4,5], {1, 2, 3}, {});").get();
|
|
|
|
auto my_list_type = list_type_impl::get_instance(int32_type, false);
|
|
auto my_set_type = set_type_impl::get_instance(int32_type, false);
|
|
auto my_map_type = map_type_impl::get_instance(utf8_type, utf8_type, false);
|
|
auto my_nonfrozen_map_type = map_type_impl::get_instance(utf8_type, utf8_type, true);
|
|
|
|
auto msg = e.execute_cql("SELECT p FROM t WHERE p CONTAINS KEY 'a' ALLOW FILTERING").get0();
|
|
assert_that(msg).is_rows().with_rows({
|
|
{my_map_type->decompose(make_map_value(my_map_type, map_type_impl::native_type({{sstring("a"), sstring("a")}})))}
|
|
});
|
|
|
|
msg = e.execute_cql("SELECT c1 FROM t WHERE c1 CONTAINS 3 ALLOW FILTERING").get0();
|
|
assert_that(msg).is_rows().with_rows({
|
|
{my_list_type->decompose(make_list_value(my_list_type, list_type_impl::native_type({{1, 2, 3}})))},
|
|
{my_list_type->decompose(make_list_value(my_list_type, list_type_impl::native_type({{2, 3, 4}})))},
|
|
{my_list_type->decompose(make_list_value(my_list_type, list_type_impl::native_type({{3, 4, 5}})))}
|
|
});
|
|
|
|
msg = e.execute_cql("SELECT c2 FROM t WHERE c2 CONTAINS 1 ALLOW FILTERING").get0();
|
|
assert_that(msg).is_rows().with_rows({
|
|
{my_set_type->decompose(make_set_value(my_set_type, set_type_impl::native_type({{1, 5}})))},
|
|
{my_set_type->decompose(make_set_value(my_set_type, set_type_impl::native_type({{1, 2, 3}})))}
|
|
});
|
|
|
|
msg = e.execute_cql("SELECT v FROM t WHERE v CONTAINS KEY 'y1' ALLOW FILTERING").get0();
|
|
assert_that(msg).is_rows().with_rows({
|
|
{my_nonfrozen_map_type->decompose(make_map_value(my_nonfrozen_map_type, map_type_impl::native_type({{sstring("x"), sstring("xyz")}, {sstring("y1"), sstring("abc")}})))},
|
|
{my_nonfrozen_map_type->decompose(make_map_value(my_nonfrozen_map_type, map_type_impl::native_type({{sstring("d"), sstring("def")}, {sstring("y1"), sstring("abc")}})))}
|
|
});
|
|
|
|
msg = e.execute_cql("SELECT c2, v FROM t WHERE v CONTAINS KEY 'y1' AND c2 CONTAINS 5 ALLOW FILTERING").get0();
|
|
assert_that(msg).is_rows().with_rows({
|
|
{
|
|
my_set_type->decompose(make_set_value(my_set_type, set_type_impl::native_type({{1, 5}}))),
|
|
my_nonfrozen_map_type->decompose(make_map_value(my_nonfrozen_map_type, map_type_impl::native_type({{sstring("x"), sstring("xyz")}, {sstring("y1"), sstring("abc")}})))
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
SEASTAR_TEST_CASE(test_in_restriction_on_not_last_partition_key) {
|
|
return do_with_cql_env_thread([] (cql_test_env& e) {
|
|
e.execute_cql("CREATE TABLE t (a int,b int,c int,d int,PRIMARY KEY ((a, b), c));").get();
|
|
e.require_table_exists("ks", "t").get();
|
|
|
|
e.execute_cql("INSERT INTO t (a,b,c,d) VALUES (1,1,1,100); ").get();
|
|
e.execute_cql("INSERT INTO t (a,b,c,d) VALUES (1,1,2,200); ").get();
|
|
e.execute_cql("INSERT INTO t (a,b,c,d) VALUES (1,1,3,300); ").get();
|
|
e.execute_cql("INSERT INTO t (a,b,c,d) VALUES (1,2,1,300); ").get();
|
|
e.execute_cql("INSERT INTO t (a,b,c,d) VALUES (1,3,1,1300);").get();
|
|
e.execute_cql("INSERT INTO t (a,b,c,d) VALUES (1,3,2,1400);").get();
|
|
e.execute_cql("INSERT INTO t (a,b,c,d) VALUES (2,3,2,1400);").get();
|
|
e.execute_cql("INSERT INTO t (a,b,c,d) VALUES (2,1,2,1400);").get();
|
|
e.execute_cql("INSERT INTO t (a,b,c,d) VALUES (2,1,3,1300);").get();
|
|
e.execute_cql("INSERT INTO t (a,b,c,d) VALUES (2,2,3,1300);").get();
|
|
e.execute_cql("INSERT INTO t (a,b,c,d) VALUES (3,1,3,1300);").get();
|
|
|
|
{
|
|
auto msg = e.execute_cql("SELECT * FROM t WHERE a IN (1,2) AND b IN (2,3) AND c>=2 AND c<=3;").get0();
|
|
assert_that(msg).is_rows().with_rows_ignore_order({
|
|
{
|
|
int32_type->decompose(1),
|
|
int32_type->decompose(3),
|
|
int32_type->decompose(2),
|
|
int32_type->decompose(1400),
|
|
},
|
|
{
|
|
int32_type->decompose(2),
|
|
int32_type->decompose(2),
|
|
int32_type->decompose(3),
|
|
int32_type->decompose(1300),
|
|
},
|
|
{
|
|
int32_type->decompose(2),
|
|
int32_type->decompose(3),
|
|
int32_type->decompose(2),
|
|
int32_type->decompose(1400),
|
|
}
|
|
});
|
|
}
|
|
{
|
|
auto msg = e.execute_cql("SELECT * FROM t WHERE a IN (1,3) AND b=1 AND c>=2 AND c<=3;").get0();
|
|
assert_that(msg).is_rows().with_rows_ignore_order({
|
|
{
|
|
int32_type->decompose(1),
|
|
int32_type->decompose(1),
|
|
int32_type->decompose(2),
|
|
int32_type->decompose(200),
|
|
},
|
|
{
|
|
int32_type->decompose(1),
|
|
int32_type->decompose(1),
|
|
int32_type->decompose(3),
|
|
int32_type->decompose(300),
|
|
},
|
|
{
|
|
int32_type->decompose(3),
|
|
int32_type->decompose(1),
|
|
int32_type->decompose(3),
|
|
int32_type->decompose(1300),
|
|
}
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
SEASTAR_TEST_CASE(test_static_multi_cell_static_lists_with_ckey) {
|
|
return do_with_cql_env_thread([] (cql_test_env& e) {
|
|
e.execute_cql("CREATE TABLE t (p int, c int, slist list<int> static, v int, PRIMARY KEY (p, c));").get();
|
|
e.execute_cql("INSERT INTO t (p, c, slist, v) VALUES (1, 1, [1], 1); ").get();
|
|
|
|
{
|
|
e.execute_cql("UPDATE t SET slist[0] = 3, v = 3 WHERE p = 1 AND c = 1;").get();
|
|
auto msg = e.execute_cql("SELECT slist, v FROM t WHERE p = 1 AND c = 1;").get0();
|
|
auto slist_type = list_type_impl::get_instance(int32_type, true);
|
|
assert_that(msg).is_rows().with_row({
|
|
{ slist_type->decompose(make_list_value(slist_type, list_type_impl::native_type({{3}}))) },
|
|
{ int32_type->decompose(3) }
|
|
});
|
|
}
|
|
{
|
|
e.execute_cql("UPDATE t SET slist = [4], v = 4 WHERE p = 1 AND c = 1;").get();
|
|
auto msg = e.execute_cql("SELECT slist, v FROM t WHERE p = 1 AND c = 1;").get0();
|
|
auto slist_type = list_type_impl::get_instance(int32_type, true);
|
|
assert_that(msg).is_rows().with_row({
|
|
{ slist_type->decompose(make_list_value(slist_type, list_type_impl::native_type({{4}}))) },
|
|
{ int32_type->decompose(4) }
|
|
});
|
|
}
|
|
{
|
|
e.execute_cql("UPDATE t SET slist = [3] + slist , v = 5 WHERE p = 1 AND c = 1;").get();
|
|
auto msg = e.execute_cql("SELECT slist, v FROM t WHERE p = 1 AND c = 1;").get0();
|
|
auto slist_type = list_type_impl::get_instance(int32_type, true);
|
|
assert_that(msg).is_rows().with_row({
|
|
{ slist_type->decompose(make_list_value(slist_type, list_type_impl::native_type({3, 4}))) },
|
|
{ int32_type->decompose(5) }
|
|
});
|
|
}
|
|
{
|
|
e.execute_cql("UPDATE t SET slist = slist + [5] , v = 6 WHERE p = 1 AND c = 1;").get();
|
|
auto msg = e.execute_cql("SELECT slist, v FROM t WHERE p = 1 AND c = 1;").get0();
|
|
auto slist_type = list_type_impl::get_instance(int32_type, true);
|
|
assert_that(msg).is_rows().with_row({
|
|
{ slist_type->decompose(make_list_value(slist_type, list_type_impl::native_type({3, 4, 5}))) },
|
|
{ int32_type->decompose(6) }
|
|
});
|
|
}
|
|
{
|
|
e.execute_cql("DELETE slist[2] from t WHERE p = 1;").get();
|
|
auto msg = e.execute_cql("SELECT slist, v FROM t WHERE p = 1 AND c = 1;").get0();
|
|
auto slist_type = list_type_impl::get_instance(int32_type, true);
|
|
assert_that(msg).is_rows().with_row({
|
|
{ slist_type->decompose(make_list_value(slist_type, list_type_impl::native_type({3, 4}))) },
|
|
{ int32_type->decompose(6) }
|
|
});
|
|
}
|
|
{
|
|
e.execute_cql("UPDATE t SET slist = slist - [4] , v = 7 WHERE p = 1 AND c = 1;").get();
|
|
auto msg = e.execute_cql("SELECT slist, v FROM t WHERE p = 1 AND c = 1;").get0();
|
|
auto slist_type = list_type_impl::get_instance(int32_type, true);
|
|
assert_that(msg).is_rows().with_row({
|
|
{ slist_type->decompose(make_list_value(slist_type, list_type_impl::native_type({3}))) },
|
|
{ int32_type->decompose(7) }
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
|
|
/**
|
|
* A class to represent a single multy-column slice expression.
|
|
* The purpose of this class is to provide facilities for testing
|
|
* the multicolumn slice expression. The class uses an abstraction
|
|
* of integer tuples with predefined max values as a counting system
|
|
* with Digits num of digits and Base-1 as the maximum value.
|
|
*
|
|
* The table this class is designed to test is a table with exactly
|
|
* Digits clustering columns of type int and at least one none clustering
|
|
* of type int.
|
|
* The none clustering column should containing the conversion of the
|
|
* clustering key into an int according to base conversion rules where the
|
|
* last clustering key is the smallest digit.
|
|
* This conversion produces a mapping from int to the tuple space spanned
|
|
* by the clustering keys of the table (including prefix tuples).
|
|
*
|
|
* The test case represent a specific slice expression and utility functions to
|
|
* run and validate it.
|
|
* For a usage example see: test_select_with_mixed_order_table
|
|
*/
|
|
template <int Base,int Digits>
|
|
class slice_testcase
|
|
{
|
|
private:
|
|
std::vector<int> _gt_range;
|
|
bool _gt_inclusive;
|
|
std::vector<int> _lt_range;
|
|
bool _lt_inclusive;
|
|
public:
|
|
/**
|
|
* The mapping of tuples is to integers between 0 and this value.
|
|
*/
|
|
static const int total_num_of_values = std::pow(Base,Digits);
|
|
|
|
/**
|
|
* Consructor for the testcase
|
|
* @param gt_range - the tuple for the greater than part of the expression
|
|
* as a vector of integers.An empty vector indicates no grater than
|
|
* part.
|
|
* @param gt_inclusive - is the greater than inclusive (>=).
|
|
* @param lt_range - the tuple for the less than part of the expression
|
|
* as a vector of integers.An empty vector indicates no less than
|
|
* part.
|
|
* @param lt_inclusive - is the less than inclusive (<=)
|
|
*/
|
|
slice_testcase(std::vector<int> gt_range, bool gt_inclusive, std::vector<int> lt_range, bool lt_inclusive) {
|
|
_gt_range = gt_range;
|
|
_lt_range = lt_range;
|
|
_gt_inclusive = gt_inclusive;
|
|
_lt_inclusive = lt_inclusive;
|
|
}
|
|
|
|
/**
|
|
* Builds a vector of the expected result assuming a select with
|
|
* this slice expression. The select is assumed to be only on the
|
|
* none clustering column.
|
|
* @return
|
|
*/
|
|
auto genrate_results_for_validation() {
|
|
std::vector<std::vector<bytes_opt>> vals;
|
|
for(auto val : generate_results()){
|
|
vals.emplace_back(std::vector<bytes_opt>{ int32_type->decompose(val) });
|
|
}
|
|
return vals;
|
|
}
|
|
|
|
/**
|
|
* Generates the actual slice expression that can be embedded
|
|
* into an SQL select query.
|
|
* @param column_names - the mames of the table clustering columns
|
|
* @return the SQL expression as a text.
|
|
*/
|
|
auto generate_cql_slice_expresion(std::vector<std::string> column_names) {
|
|
std::string expression;
|
|
if (!_gt_range.empty()) {
|
|
expression += "(";
|
|
expression += column_names[0];
|
|
for(std::size_t i=1; i < _gt_range.size(); i++) {
|
|
expression += ", "+column_names[i];
|
|
}
|
|
expression += ") ";
|
|
expression += _gt_inclusive ? ">= " : "> ";
|
|
expression += "(";
|
|
expression += std::to_string(_gt_range[0]);
|
|
for(std::size_t i=1; i<_gt_range.size(); i++) {
|
|
expression += ", ";
|
|
expression += std::to_string(_gt_range[i]);
|
|
}
|
|
expression += ")";
|
|
}
|
|
if (!_gt_range.empty() && !_lt_range.empty()) {
|
|
expression += " AND ";
|
|
}
|
|
if (!_lt_range.empty()) {
|
|
expression += "(";
|
|
expression += column_names[0];
|
|
for(std::size_t i=1; i < _lt_range.size(); i++) {
|
|
expression += ", ";
|
|
expression += column_names[i];
|
|
}
|
|
expression += ") ";
|
|
expression += _lt_inclusive ? "<= " : "< ";
|
|
|
|
expression += "(";
|
|
expression += std::to_string(_lt_range[0]);
|
|
for(std::size_t i=1; i < _lt_range.size(); i++) {
|
|
expression += ", ";
|
|
expression += std::to_string(_lt_range[i]);
|
|
}
|
|
expression += ")";
|
|
}
|
|
return expression;
|
|
}
|
|
|
|
/**
|
|
* Maps a tuple of integers to integer
|
|
* @param tuple - the tuple to convert as a vector of integers.
|
|
* @return the integer this tuple is mapped to.
|
|
*/
|
|
static int tuple_to_bound_val(std::vector<int> tuple) {
|
|
int ret = 0;
|
|
int factor = std::pow(Base, Digits-1);
|
|
for (int val : tuple) {
|
|
ret += val * factor;
|
|
factor /= Base;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* Maps back from integer space to tuple space.
|
|
* There can be more than one tuple maped to the same int.
|
|
* There will never be more than one tuple of a certain size
|
|
* that is maped to the same int.
|
|
* For example: (1) and (1,0) will be maped to the same integer,
|
|
* but no other tuple of size 1 or 2 will be maped to this int.
|
|
* @param val - the value to map
|
|
* @param num_componnents - the size of the produced tuple.
|
|
* @return the tuple of the requested size.
|
|
*/
|
|
static auto bound_val_to_tuple(int val, std::size_t num_componnents = Digits) {
|
|
std::vector<int> tuple;
|
|
int factor = std::pow(Base, Digits-1);
|
|
while (tuple.size() < num_componnents) {
|
|
tuple.emplace_back(val/factor);
|
|
val %= factor;
|
|
factor /= Base;
|
|
}
|
|
return tuple;
|
|
}
|
|
private:
|
|
/**
|
|
* A helper function to generate the expected results of a select
|
|
* statement with this slice. The select statement is assumed to
|
|
* select only the none clustering column.
|
|
* @return a vector of integers representing the expected results.
|
|
*/
|
|
std::vector<int> generate_results() {
|
|
std::vector<int> vals;
|
|
int start_val = 0;
|
|
int end_val = total_num_of_values -1;
|
|
if (!_gt_range.empty()) {
|
|
start_val = tuple_to_bound_val(_gt_range);
|
|
if (!_gt_inclusive) {
|
|
start_val += std::pow(Base,Digits - _gt_range.size());
|
|
}
|
|
}
|
|
if (!_lt_range.empty()) {
|
|
end_val = tuple_to_bound_val(_lt_range);
|
|
if (!_lt_inclusive) {
|
|
end_val--;
|
|
} else {
|
|
end_val += std::pow(Base, Digits - _lt_range.size()) - 1;
|
|
}
|
|
}
|
|
for (int i=start_val; i<=end_val; i++) {
|
|
vals.emplace_back(i);
|
|
}
|
|
return vals;
|
|
}
|
|
};
|
|
|
|
|
|
SEASTAR_TEST_CASE(test_select_with_mixed_order_table) {
|
|
using slice_test_type = slice_testcase<5,4>;
|
|
return do_with_cql_env_thread([] (cql_test_env& e) {
|
|
std::string select_query_template = "SELECT f FROM foo WHERE a=0 AND %s;";
|
|
std::vector<std::string> column_names = { "b", "c", "d", "e" };
|
|
e.execute_cql("CREATE TABLE foo (a int, b int, c int,d int,e int,f int, PRIMARY KEY (a, b, c, d, e)) WITH CLUSTERING ORDER BY (b DESC, c ASC, d DESC,e ASC);").get();
|
|
e.require_table_exists("ks", "foo").get();
|
|
|
|
// We convert the range 0-> max mapped integers to the mapped tuple,
|
|
// this will create a table satisfying the slice_testcase assumption.
|
|
for(int i=0; i < slice_test_type::total_num_of_values; i++) {
|
|
auto tuple = slice_test_type::bound_val_to_tuple(i);
|
|
e.execute_cql(format("INSERT INTO foo (a, b, c, d, e, f) VALUES (0, {}, {}, {}, {}, {});",
|
|
tuple[0],tuple[1],tuple[2],tuple[3],i)).get();
|
|
}
|
|
|
|
// a vector to hold all test cases.
|
|
std::vector<slice_test_type> test_cases;
|
|
|
|
//generates all inclusiveness permutations for the specified bounds
|
|
auto generate_with_inclusiveness_permutations = [&test_cases] (std::vector<int> gt_range,std::vector<int> lt_range) {
|
|
if(gt_range.empty() || lt_range.empty()) {
|
|
test_cases.emplace_back(slice_test_type{gt_range, false, lt_range,false});
|
|
test_cases.emplace_back(slice_test_type{gt_range, true, lt_range,true});
|
|
} else {
|
|
for(int i=0; i<=3; i++) {
|
|
test_cases.emplace_back(slice_test_type{gt_range, i&1, lt_range, i&2});
|
|
}
|
|
}
|
|
};
|
|
|
|
|
|
// no overlap in componnents equal num of componnents - (b,c,d,e) >/>= (0,1,2,3) and (b,c,d,e) </<= (1,2,3,4)
|
|
generate_with_inclusiveness_permutations({0,1,2,3},{1,2,3,4});
|
|
// overlap in componnents equal num of componnents - (b,c,d,e) >/>= (0,1,2,3) and (b,c,d,e) </<= (0,2,2,2)
|
|
generate_with_inclusiveness_permutations({0,1,2,3},{0,2,2,2});
|
|
// overlap in componnents equal num of componnents - (b,c,d,e) >/>= (0,1,2,3) and (b,c,d,e) </<= (0,1,2,2)
|
|
generate_with_inclusiveness_permutations({0,1,2,3},{0,1,2,2});
|
|
// no overlap less compnnents in </<= expression - (b,c,d,e) >/>= (0,1,2,3) and (b,c) </<= (1,2)
|
|
generate_with_inclusiveness_permutations({0,1,2,3},{1,2});
|
|
// overlap in compnnents for less componnents in </<= expression - (b,c,d,e) >/>= (0,1,2,3) and (b,c) </<= (0,2)
|
|
generate_with_inclusiveness_permutations({0,1,2,3},{0,2});
|
|
// lt side is a prefix of gt side </<= expression - (b,c,d,e) >/>= (0,1,2,3) and (b,c) </<= (0,1)
|
|
generate_with_inclusiveness_permutations({0,1,2,3},{0,1});
|
|
// gt side is a prefix of lt side </<= expression - (b,c,d,e) >/>= (0,1) and (b,c) </<= (0,1,2,3)
|
|
generate_with_inclusiveness_permutations({0,1},{0,1,2,3});
|
|
// no overlap less compnnents in >/>= expression - (b,c) >/>= (0,1) and (b,c,d,e) </<= (1,2,3,4)
|
|
generate_with_inclusiveness_permutations({0,1},{1,2,3,4});
|
|
// overlap in compnnents for less componnents in >/>= expression - (b,c) >/>= (0,1) and (b,c,d,e) </<= (0,2,3,4)
|
|
generate_with_inclusiveness_permutations({0,1},{0,2,3,4});
|
|
// one sided >/>= 1 expression - (b) >/>= (1)
|
|
generate_with_inclusiveness_permutations({1},{});
|
|
// one sided >/>= partial expression - (b,c) >/>= (0,1)
|
|
generate_with_inclusiveness_permutations({0,1},{});
|
|
// one sided >/>= full expression - (b,c,d,e) >/>= (0,1,2,3)
|
|
generate_with_inclusiveness_permutations({0,1,2,3},{});
|
|
// one sided </<= 1 expression - - (b) </<= (3)
|
|
generate_with_inclusiveness_permutations({},{3});
|
|
// one sided </<= partial expression - (b,c) </<= (3,4)
|
|
generate_with_inclusiveness_permutations({},{3,4});
|
|
// one sided </<= full expression - (b,c,d,e) </<= (2,3,4,4)
|
|
generate_with_inclusiveness_permutations({},{2,3,4,4});
|
|
// equality and empty - (b,c,d,e) >/>= (0,1,2,3) and (b,c,d,e) </<= (0,1,2,3)
|
|
generate_with_inclusiveness_permutations({0,1,2,3},{0,1,2,3});
|
|
|
|
for (auto&& test_case : test_cases) {
|
|
auto msg = e.execute_cql(sprint(select_query_template,test_case.generate_cql_slice_expresion(column_names))).get0();
|
|
assert_that(msg).is_rows().with_rows_ignore_order(test_case.genrate_results_for_validation());
|
|
}
|
|
});
|
|
}
|
|
|
|
SEASTAR_TEST_CASE(test_filtering) {
|
|
return do_with_cql_env_thread([] (cql_test_env& e) {
|
|
e.execute_cql("CREATE TABLE cf (k int, v int,m int,n int,o int,p int static, PRIMARY KEY ((k,v),m,n));").get();
|
|
e.execute_cql(
|
|
"BEGIN UNLOGGED BATCH \n"
|
|
"INSERT INTO cf (k, v, m, n, o, p) VALUES (1, 1, 1, 1, 1 ,1 ); \n"
|
|
"INSERT INTO cf (k, v, m, n, o, p) VALUES (2, 1, 2, 1, 2 ,2 ); \n"
|
|
"INSERT INTO cf (k, v, m, n, o, p) VALUES (3, 1, 3, 1, 3 ,3 ); \n"
|
|
"INSERT INTO cf (k, v, m, n, o, p) VALUES (4, 2, 1, 2, 4 ,4 ); \n"
|
|
"INSERT INTO cf (k, v, m, n, o, p) VALUES (5, 2, 2, 2, 5 ,5 ); \n"
|
|
"INSERT INTO cf (k, v, m, n, o, p) VALUES (6, 2, 3, 2, 6 ,6 ); \n"
|
|
"INSERT INTO cf (k, v, m, n, o, p) VALUES (7, 3, 1, 3, 7 ,7 ); \n"
|
|
"INSERT INTO cf (k, v, m, n, o, p) VALUES (8, 3, 2, 3, 8 ,8 ); \n"
|
|
"INSERT INTO cf (k, v, m, n, o, p) VALUES (9, 3, 3, 3, 9 ,9 ); \n"
|
|
"INSERT INTO cf (k, v, m, n, o, p) VALUES (10, 4, 1, 4,10,10); \n"
|
|
"INSERT INTO cf (k, v, m, n, o, p) VALUES (11, 4, 2, 4,11,11); \n"
|
|
"INSERT INTO cf (k, v, m, n, o, p) VALUES (12, 5, 3, 5,12,12); \n"
|
|
"INSERT INTO cf (k, v, m, n, o, p) VALUES (12, 5, 4, 5,13,13); \n"
|
|
"APPLY BATCH;"
|
|
).get();
|
|
|
|
// Notice the with_serialized_columns_count() check before the set comparison.
|
|
// Since we are dealing with the result set before serializing to the client,
|
|
// there is an extra column that is used for the filtering, this column will
|
|
// not be present in the responce to the client and with_serialized_columns_count()
|
|
// verifies exactly that.
|
|
|
|
// test filtering on partition keys
|
|
{
|
|
auto msg = e.execute_cql("SELECT k FROM cf WHERE v=3 ALLOW FILTERING;").get0();
|
|
assert_that(msg).is_rows().with_serialized_columns_count(1).with_rows_ignore_order({
|
|
{ int32_type->decompose(7), int32_type->decompose(3)},
|
|
{ int32_type->decompose(8), int32_type->decompose(3) },
|
|
{ int32_type->decompose(9), int32_type->decompose(3) },
|
|
});
|
|
}
|
|
|
|
// test filtering on clustering keys
|
|
{
|
|
auto msg = e.execute_cql("SELECT k FROM cf WHERE n=4 ALLOW FILTERING;").get0();
|
|
assert_that(msg).is_rows().with_serialized_columns_count(1).with_rows_ignore_order({
|
|
{ int32_type->decompose(10), int32_type->decompose(4) },
|
|
{ int32_type->decompose(11), int32_type->decompose(4) },
|
|
});
|
|
}
|
|
|
|
//test filtering on regular columns
|
|
{
|
|
auto msg = e.execute_cql("SELECT k FROM cf WHERE o>7 ALLOW FILTERING;").get0();
|
|
assert_that(msg).is_rows().with_serialized_columns_count(1).with_rows_ignore_order({
|
|
{ int32_type->decompose(8), int32_type->decompose(8) },
|
|
{ int32_type->decompose(9), int32_type->decompose(9) },
|
|
{ int32_type->decompose(10), int32_type->decompose(10) },
|
|
{ int32_type->decompose(11), int32_type->decompose(11) },
|
|
{ int32_type->decompose(12), int32_type->decompose(12) },
|
|
{ int32_type->decompose(12), int32_type->decompose(13) },
|
|
});
|
|
}
|
|
|
|
//test filtering on static columns
|
|
{
|
|
auto msg = e.execute_cql("SELECT k FROM cf WHERE p>=10 AND p<=12 ALLOW FILTERING;").get0();
|
|
assert_that(msg).is_rows().with_serialized_columns_count(1).with_rows_ignore_order({
|
|
{ int32_type->decompose(10), int32_type->decompose(10) },
|
|
{ int32_type->decompose(11), int32_type->decompose(11) },
|
|
});
|
|
}
|
|
//test filtering with count
|
|
{
|
|
auto msg = e.execute_cql("SELECT COUNT(k) FROM cf WHERE n>3 ALLOW FILTERING;").get0();
|
|
assert_that(msg).is_rows().with_serialized_columns_count(1).with_size(1).with_rows_ignore_order({
|
|
{ long_type->decompose(4L), int32_type->decompose(4) },
|
|
});
|
|
}
|
|
|
|
});
|
|
}
|