before this change, we rely on `using namespace seastar` to use
`seastar::format()` without qualifying the `format()` with its
namespace. this works fine until we changed the parameter type
of format string `seastar::format()` from `const char*` to
`fmt::format_string<...>`. this change practically invited
`seastar::format()` to the club of `std::format()` and `fmt::format()`,
where all members accept a templated parameter as its `fmt`
parameter. and `seastar::format()` is not the best candidate anymore.
despite that argument-dependent lookup (ADT for short) favors the
function which is in the same namespace as its parameter, but
`using namespace` makes `seastar::format()` more competitive,
so both `std::format()` and `seastar::format()` are considered
as the condidates.
that is what is happening scylladb in quite a few caller sites of
`format()`, hence ADT is not able to tell which function the winner
in the name lookup:
```
/__w/scylladb/scylladb/mutation/mutation_fragment_stream_validator.cc:265:12: error: call to 'format' is ambiguous
265 | return format("{} ({}.{} {})", _name_view, s.ks_name(), s.cf_name(), s.id());
| ^~~~~~
/usr/bin/../lib/gcc/x86_64-redhat-linux/14/../../../../include/c++/14/format:4290:5: note: candidate function [with _Args = <const std::basic_string_view<char> &, const seastar::basic_sstring<char, unsigned int, 15> &, const seastar::basic_sstring<char, unsigned int, 15> &, const utils::tagged_uuid<table_id_tag> &>]
4290 | format(format_string<_Args...> __fmt, _Args&&... __args)
| ^
/__w/scylladb/scylladb/seastar/include/seastar/core/print.hh:143:1: note: candidate function [with A = <const std::basic_string_view<char> &, const seastar::basic_sstring<char, unsigned int, 15> &, const seastar::basic_sstring<char, unsigned int, 15> &, const utils::tagged_uuid<table_id_tag> &>]
143 | format(fmt::format_string<A...> fmt, A&&... a) {
| ^
```
in this change, we
change all `format()` to either `fmt::format()` or `seastar::format()`
with following rules:
- if the caller expects an `sstring` or `std::string_view`, change to
`seastar::format()`
- if the caller expects an `std::string`, change to `fmt::format()`.
because, `sstring::operator std::basic_string` would incur a deep
copy.
we will need another change to enable scylladb to compile with the
latest seastar. namely, to pass the format string as a templated
parameter down to helper functions which format their parameters.
to miminize the scope of this change, let's include that change when
bumping up the seastar submodule. as that change will depend on
the seastar change.
Signed-off-by: Kefu Chai <kefu.chai@scylladb.com>
613 lines
25 KiB
C++
613 lines
25 KiB
C++
/*
|
|
* Copyright (C) 2022-present ScyllaDB
|
|
*/
|
|
|
|
/*
|
|
* SPDX-License-Identifier: AGPL-3.0-or-later
|
|
*/
|
|
|
|
#include "expr_test_utils.hh"
|
|
#include <fmt/ranges.h>
|
|
|
|
namespace cql3 {
|
|
namespace expr {
|
|
namespace test_utils {
|
|
template <class T>
|
|
requires (!requires (T t) { t.has_value(); })
|
|
raw_value make_raw(T t) {
|
|
data_type val_type = data_type_for<T>();
|
|
data_value data_val(t);
|
|
return raw_value::make_value(val_type->decompose(data_val));
|
|
}
|
|
|
|
template <class T>
|
|
raw_value make_raw(std::optional<T> t) {
|
|
if (t.has_value()) {
|
|
return make_raw(t.value());
|
|
} else {
|
|
return raw_value::make_null();
|
|
}
|
|
}
|
|
|
|
raw_value make_empty_raw() {
|
|
return raw_value::make_value(managed_bytes());
|
|
}
|
|
|
|
raw_value make_bool_raw(bool val) {
|
|
return make_raw(val);
|
|
}
|
|
|
|
raw_value make_tinyint_raw(int8_t val) {
|
|
return make_raw(val);
|
|
}
|
|
|
|
raw_value make_smallint_raw(int16_t val) {
|
|
return make_raw(val);
|
|
}
|
|
|
|
raw_value make_int_raw(int32_t val) {
|
|
return make_raw(val);
|
|
}
|
|
|
|
raw_value make_bigint_raw(int64_t val) {
|
|
return make_raw(val);
|
|
}
|
|
|
|
raw_value make_text_raw(const sstring_view& text) {
|
|
return raw_value::make_value(utf8_type->decompose(text));
|
|
}
|
|
|
|
raw_value make_float_raw(float val) {
|
|
return make_raw(val);
|
|
}
|
|
|
|
raw_value make_double_raw(double val) {
|
|
return make_raw(val);
|
|
}
|
|
|
|
template <class T>
|
|
constant make_const(T t) {
|
|
data_type val_type = data_type_for<T>();
|
|
return constant(make_raw(t), val_type);
|
|
}
|
|
|
|
constant make_empty_const(data_type type) {
|
|
return constant(make_empty_raw(), type);
|
|
}
|
|
|
|
constant make_bool_const(bool val) {
|
|
return make_const(val);
|
|
}
|
|
|
|
constant make_tinyint_const(int8_t val) {
|
|
return make_const(val);
|
|
}
|
|
|
|
constant make_smallint_const(int16_t val) {
|
|
return make_const(val);
|
|
}
|
|
|
|
constant make_int_const(int32_t val) {
|
|
return make_const(val);
|
|
}
|
|
|
|
constant make_bigint_const(int64_t val) {
|
|
return make_const(val);
|
|
}
|
|
|
|
constant make_text_const(const sstring_view& text) {
|
|
return constant(make_text_raw(text), utf8_type);
|
|
}
|
|
|
|
constant make_float_const(float val) {
|
|
return make_const(val);
|
|
}
|
|
|
|
constant make_double_const(double val) {
|
|
return make_const(val);
|
|
}
|
|
|
|
untyped_constant make_int_untyped(const char* raw_text) {
|
|
return untyped_constant{.partial_type = untyped_constant::type_class::integer, .raw_text = raw_text};
|
|
}
|
|
|
|
untyped_constant make_float_untyped(const char* raw_text) {
|
|
return untyped_constant{.partial_type = untyped_constant::type_class::floating_point, .raw_text = raw_text};
|
|
}
|
|
|
|
untyped_constant make_string_untyped(const char* raw_text) {
|
|
return untyped_constant{.partial_type = untyped_constant::type_class::string, .raw_text = raw_text};
|
|
}
|
|
|
|
untyped_constant make_bool_untyped(const char* raw_text) {
|
|
return untyped_constant{.partial_type = untyped_constant::type_class::boolean, .raw_text = raw_text};
|
|
}
|
|
|
|
untyped_constant make_duration_untyped(const char* raw_text) {
|
|
return untyped_constant{.partial_type = untyped_constant::type_class::duration, .raw_text = raw_text};
|
|
}
|
|
|
|
untyped_constant make_uuid_untyped(const char* raw_text) {
|
|
return untyped_constant{.partial_type = untyped_constant::type_class::uuid, .raw_text = raw_text};
|
|
}
|
|
|
|
untyped_constant make_hex_untyped(const char* raw_text) {
|
|
return untyped_constant{.partial_type = untyped_constant::type_class::hex, .raw_text = raw_text};
|
|
}
|
|
|
|
untyped_constant make_null_untyped() {
|
|
return untyped_constant{.partial_type = untyped_constant::type_class::null, .raw_text = "null"};
|
|
}
|
|
|
|
// This function implements custom serialization of collection values.
|
|
// Some tests require the collection to contain an empty value,
|
|
// which is impossible to express using the existing code.
|
|
cql3::raw_value make_collection_raw(size_t size_to_write, const std::vector<cql3::raw_value>& elements_to_write) {
|
|
size_t serialized_len = 0;
|
|
serialized_len += collection_size_len();
|
|
for (const cql3::raw_value& val : elements_to_write) {
|
|
serialized_len += collection_value_len();
|
|
if (val.is_value()) {
|
|
serialized_len += val.view().with_value([](const FragmentedView auto& view) { return view.size_bytes(); });
|
|
}
|
|
}
|
|
|
|
bytes b(bytes::initialized_later(), serialized_len);
|
|
bytes::iterator out = b.begin();
|
|
|
|
write_collection_size(out, size_to_write);
|
|
for (const cql3::raw_value& val : elements_to_write) {
|
|
if (val.is_null()) {
|
|
write_int32(out, -1);
|
|
} else {
|
|
val.view().with_value(
|
|
[&](const FragmentedView auto& val_view) { write_collection_value(out, linearized(val_view)); });
|
|
}
|
|
}
|
|
|
|
return cql3::raw_value::make_value(b);
|
|
}
|
|
|
|
raw_value make_list_raw(const std::vector<raw_value>& values) {
|
|
return make_collection_raw(values.size(), values);
|
|
}
|
|
|
|
raw_value make_set_raw(const std::vector<raw_value>& values) {
|
|
return make_collection_raw(values.size(), values);
|
|
}
|
|
|
|
raw_value make_map_raw(const std::vector<std::pair<raw_value, raw_value>>& values) {
|
|
std::vector<raw_value> flattened_values;
|
|
for (const std::pair<raw_value, raw_value>& pair_val : values) {
|
|
flattened_values.push_back(pair_val.first);
|
|
flattened_values.push_back(pair_val.second);
|
|
}
|
|
return make_collection_raw(values.size(), flattened_values);
|
|
}
|
|
|
|
// This function implements custom serialization of tuples.
|
|
// Some tests require the tuple to contain an empty value,
|
|
// which is impossible to express using the existing code.
|
|
raw_value make_tuple_raw(const std::vector<raw_value>& values) {
|
|
size_t serialized_len = 0;
|
|
for (const raw_value& val : values) {
|
|
serialized_len += 4;
|
|
if (val.is_value()) {
|
|
serialized_len += val.view().size_bytes();
|
|
}
|
|
}
|
|
managed_bytes ret(managed_bytes::initialized_later(), serialized_len);
|
|
managed_bytes_mutable_view out(ret);
|
|
for (const raw_value& val : values) {
|
|
if (val.is_null()) {
|
|
write<int32_t>(out, -1);
|
|
} else {
|
|
val.view().with_value([&](const FragmentedView auto& bytes_view) {
|
|
write<int32_t>(out, bytes_view.size_bytes());
|
|
write_fragmented(out, bytes_view);
|
|
});
|
|
}
|
|
}
|
|
return raw_value::make_value(std::move(ret));
|
|
}
|
|
|
|
template <class T>
|
|
raw_value to_raw_value(const T& t) {
|
|
if constexpr (std::same_as<T, raw_value>) {
|
|
return t;
|
|
} else if constexpr (std::same_as<T, constant>) {
|
|
return t.value;
|
|
} else {
|
|
return make_raw<T>(t);
|
|
}
|
|
}
|
|
|
|
// A concept which expresses that it's possible to convert T to raw_value.
|
|
// Satisfied for raw_value, constant, int32_t, and various other types.
|
|
template <class T>
|
|
concept ToRawValue = requires(T t) {
|
|
data_value(t);
|
|
{ to_raw_value(t) } -> std::same_as<raw_value>;
|
|
}
|
|
|| std::same_as<T, constant> || std::same_as<T, raw_value>;
|
|
|
|
template <ToRawValue T>
|
|
std::vector<raw_value> to_raw_values(const std::vector<T>& values) {
|
|
std::vector<raw_value> raw_vals;
|
|
for (const T& val : values) {
|
|
raw_vals.push_back(to_raw_value(val));
|
|
}
|
|
return raw_vals;
|
|
}
|
|
|
|
template <ToRawValue T1, ToRawValue T2>
|
|
std::vector<std::pair<raw_value, raw_value>> to_raw_value_pairs(const std::vector<std::pair<T1, T2>>& values) {
|
|
std::vector<std::pair<raw_value, raw_value>> raw_vals;
|
|
for (const std::pair<T1, T2>& val : values) {
|
|
raw_vals.emplace_back(to_raw_value(val.first), to_raw_value(val.second));
|
|
}
|
|
return raw_vals;
|
|
}
|
|
|
|
constant make_list_const(const std::vector<raw_value>& vals, data_type elements_type) {
|
|
raw_value raw_list = make_list_raw(vals);
|
|
data_type list_type = list_type_impl::get_instance(elements_type, true);
|
|
return constant(std::move(raw_list), std::move(list_type));
|
|
}
|
|
|
|
constant make_list_const(const std::vector<constant>& vals, data_type elements_type) {
|
|
return make_list_const(to_raw_values(vals), elements_type);
|
|
}
|
|
|
|
constant make_set_const(const std::vector<raw_value>& vals, data_type elements_type) {
|
|
raw_value raw_set = make_set_raw(vals);
|
|
data_type set_type = set_type_impl::get_instance(elements_type, true);
|
|
return constant(std::move(raw_set), std::move(set_type));
|
|
}
|
|
|
|
constant make_set_const(const std::vector<constant>& vals, data_type elements_type) {
|
|
return make_set_const(to_raw_values(vals), elements_type);
|
|
}
|
|
|
|
constant make_map_const(const std::vector<std::pair<raw_value, raw_value>>& vals,
|
|
data_type key_type,
|
|
data_type value_type) {
|
|
raw_value raw_map = make_map_raw(vals);
|
|
data_type map_type = map_type_impl::get_instance(key_type, value_type, true);
|
|
return constant(std::move(raw_map), std::move(map_type));
|
|
}
|
|
|
|
constant make_map_const(const std::vector<std::pair<constant, constant>>& vals,
|
|
data_type key_type,
|
|
data_type value_type) {
|
|
return make_map_const(to_raw_value_pairs(vals), key_type, value_type);
|
|
}
|
|
|
|
constant make_tuple_const(const std::vector<raw_value>& vals, const std::vector<data_type>& element_types) {
|
|
raw_value raw_tuple = make_tuple_raw(vals);
|
|
data_type tuple_type = tuple_type_impl::get_instance(element_types);
|
|
return constant(std::move(raw_tuple), std::move(tuple_type));
|
|
}
|
|
|
|
constant make_tuple_const(const std::vector<constant>& vals, const std::vector<data_type>& element_types) {
|
|
return test_utils::make_tuple_const(to_raw_values(vals), element_types);
|
|
}
|
|
|
|
raw_value make_int_list_raw(const std::vector<std::optional<int32_t>>& values) {
|
|
return make_list_raw(to_raw_values(values));
|
|
}
|
|
|
|
raw_value make_int_set_raw(const std::vector<int32_t>& values) {
|
|
return make_set_raw(to_raw_values(values));
|
|
}
|
|
|
|
raw_value make_int_int_map_raw(const std::vector<std::pair<int32_t, int32_t>>& values) {
|
|
return make_map_raw(to_raw_value_pairs(values));
|
|
}
|
|
|
|
constant make_int_list_const(const std::vector<std::optional<int32_t>>& values) {
|
|
return constant(make_int_list_raw(values), list_type_impl::get_instance(int32_type, true));
|
|
}
|
|
|
|
constant make_int_set_const(const std::vector<int32_t>& values) {
|
|
return constant(make_int_set_raw(values), set_type_impl::get_instance(int32_type, true));
|
|
}
|
|
|
|
constant make_int_int_map_const(const std::vector<std::pair<int32_t, int32_t>>& values) {
|
|
return constant(make_int_int_map_raw(values), map_type_impl::get_instance(int32_type, int32_type, true));
|
|
}
|
|
|
|
collection_constructor make_list_constructor(std::vector<expression> elements, data_type elements_type) {
|
|
return collection_constructor{.style = collection_constructor::style_type::list,
|
|
.elements = std::move(elements),
|
|
.type = list_type_impl::get_instance(elements_type, true)};
|
|
}
|
|
|
|
collection_constructor make_set_constructor(std::vector<expression> elements, data_type elements_type) {
|
|
return collection_constructor{.style = collection_constructor::style_type::set,
|
|
.elements = std::move(elements),
|
|
.type = set_type_impl::get_instance(elements_type, true)};
|
|
}
|
|
|
|
collection_constructor make_map_constructor(const std::vector<expression> elements,
|
|
data_type key_type,
|
|
data_type element_type) {
|
|
return collection_constructor{.style = collection_constructor::style_type::map,
|
|
.elements = std::move(elements),
|
|
.type = map_type_impl::get_instance(key_type, element_type, true)};
|
|
}
|
|
|
|
collection_constructor make_map_constructor(const std::vector<std::pair<expression, expression>>& elements,
|
|
data_type key_type,
|
|
data_type element_type) {
|
|
std::vector<expression> map_element_pairs;
|
|
for (const std::pair<expression, expression>& element : elements) {
|
|
map_element_pairs.push_back(tuple_constructor{.elements = {element.first, element.second},
|
|
.type = tuple_type_impl::get_instance({key_type, element_type})});
|
|
}
|
|
return make_map_constructor(map_element_pairs, key_type, element_type);
|
|
}
|
|
|
|
tuple_constructor make_tuple_constructor(std::vector<expression> elements, std::vector<data_type> element_types) {
|
|
return tuple_constructor{.elements = std::move(elements),
|
|
.type = tuple_type_impl::get_instance(std::move(element_types))};
|
|
}
|
|
|
|
usertype_constructor make_usertype_constructor(std::vector<std::pair<sstring_view, constant>> field_values) {
|
|
usertype_constructor::elements_map_type elements_map;
|
|
std::vector<bytes> field_names;
|
|
std::vector<data_type> field_types;
|
|
for (auto& [field_name, field_value] : field_values) {
|
|
field_names.push_back(field_name.data());
|
|
field_types.push_back(field_value.type);
|
|
elements_map.emplace(column_identifier(sstring(field_name), true), field_value);
|
|
}
|
|
data_type type = user_type_impl::get_instance("test_ks", "test_user_type", field_names, field_types, true);
|
|
return usertype_constructor{.elements = std::move(elements_map), .type = std::move(type)};
|
|
}
|
|
|
|
::lw_shared_ptr<column_specification> make_receiver(data_type receiver_type, sstring receiver_name) {
|
|
return ::make_lw_shared<column_specification>(
|
|
"test_ks", "test_cf", ::make_shared<cql3::column_identifier>(receiver_name, true), receiver_type);
|
|
}
|
|
|
|
// Creates evaluation_inputs that can be used to evaluate columns and bind variables using evaluate()
|
|
std::pair<evaluation_inputs, std::unique_ptr<evaluation_inputs_data>> make_evaluation_inputs(
|
|
const schema_ptr& table_schema,
|
|
const column_values& column_vals,
|
|
const std::vector<raw_value>& bind_marker_values) {
|
|
auto throw_error = [&](const auto&... fmt_args) -> sstring {
|
|
sstring error_msg = seastar::format(fmt_args...);
|
|
sstring final_msg = seastar::format("make_evaluation_inputs error: {}. (table_schema: {}, column_vals: {})", error_msg,
|
|
*table_schema, column_vals);
|
|
throw std::runtime_error(final_msg);
|
|
};
|
|
|
|
auto get_col_val = [&](const column_definition& col) -> const mutation_column_value& {
|
|
auto col_value_iter = column_vals.find(col.name_as_text());
|
|
if (col_value_iter == column_vals.end()) {
|
|
throw_error("no value for column {}", col.name_as_text());
|
|
}
|
|
return col_value_iter->second;
|
|
};
|
|
|
|
std::vector<bytes> partition_key;
|
|
for (const column_definition& pk_col : table_schema->partition_key_columns()) {
|
|
const raw_value& col_value = get_col_val(pk_col).value;
|
|
|
|
if (col_value.is_null()) {
|
|
throw_error("Passed NULL as value for {}. This is not allowed for partition key columns.",
|
|
pk_col.name_as_text());
|
|
}
|
|
partition_key.push_back(raw_value(col_value).to_bytes());
|
|
}
|
|
|
|
std::vector<bytes> clustering_key;
|
|
for (const column_definition& ck_col : table_schema->clustering_key_columns()) {
|
|
const raw_value& col_value = get_col_val(ck_col).value;
|
|
|
|
if (col_value.is_null()) {
|
|
throw_error("Passed NULL as value for {}. This is not allowed for clustering key columns.",
|
|
ck_col.name_as_text());
|
|
}
|
|
clustering_key.push_back(raw_value(col_value).to_bytes());
|
|
}
|
|
|
|
std::vector<const column_definition*> selection_columns;
|
|
for (const column_definition& cdef : table_schema->regular_columns()) {
|
|
selection_columns.push_back(&cdef);
|
|
}
|
|
for (const column_definition& cdef : table_schema->static_columns()) {
|
|
selection_columns.push_back(&cdef);
|
|
}
|
|
|
|
::shared_ptr<selection::selection> selection =
|
|
cql3::selection::selection::for_columns(table_schema, std::move(selection_columns));
|
|
std::vector<managed_bytes_opt> static_and_regular_columns(table_schema->regular_columns_count() +
|
|
table_schema->static_columns_count());
|
|
std::vector<api::timestamp_type> static_and_regular_column_timestamps(static_and_regular_columns.size());
|
|
std::vector<int32_t> static_and_regular_column_ttls(static_and_regular_columns.size());
|
|
|
|
for (const column_definition& col : table_schema->regular_columns()) {
|
|
auto& mut_value = get_col_val(col);
|
|
const raw_value& col_value = mut_value.value;
|
|
int32_t index = selection->index_of(col);
|
|
static_and_regular_columns[index] = raw_value(col_value).to_managed_bytes_opt();
|
|
static_and_regular_column_timestamps[index] = mut_value.timestamp;
|
|
static_and_regular_column_ttls[index] = mut_value.ttl;
|
|
}
|
|
|
|
for (const column_definition& col : table_schema->static_columns()) {
|
|
auto& mut_value = get_col_val(col);
|
|
const raw_value& col_value = mut_value.value;
|
|
int32_t index = selection->index_of(col);
|
|
static_and_regular_columns[index] = raw_value(col_value).to_managed_bytes_opt();
|
|
static_and_regular_column_timestamps[index] = mut_value.timestamp;
|
|
static_and_regular_column_ttls[index] = mut_value.ttl;
|
|
}
|
|
|
|
query_options options(default_cql_config, db::consistency_level::ONE, std::nullopt, bind_marker_values, true,
|
|
query_options::specific_options::DEFAULT);
|
|
|
|
std::unique_ptr<evaluation_inputs_data> data = std::make_unique<evaluation_inputs_data>(
|
|
evaluation_inputs_data{.partition_key = std::move(partition_key),
|
|
.clustering_key = std::move(clustering_key),
|
|
.static_and_regular_columns = std::move(static_and_regular_columns),
|
|
.selection = std::move(selection),
|
|
.options = std::move(options),
|
|
.timestamps = std::move(static_and_regular_column_timestamps),
|
|
.ttls = std::move(static_and_regular_column_ttls)});
|
|
|
|
evaluation_inputs inputs{.partition_key = data->partition_key,
|
|
.clustering_key = data->clustering_key,
|
|
.static_and_regular_columns = data->static_and_regular_columns,
|
|
.selection = data->selection.get(),
|
|
.options = &data->options,
|
|
.static_and_regular_timestamps = data->timestamps,
|
|
.static_and_regular_ttls = data->ttls,
|
|
};
|
|
|
|
return std::pair(std::move(inputs), std::move(data));
|
|
}
|
|
|
|
bind_variable
|
|
make_bind_variable(int32_t index, data_type type) {
|
|
return bind_variable{index, make_receiver(type, "?")};
|
|
}
|
|
|
|
raw_value
|
|
evaluate_with_bind_variables(const expression& e, std::vector<raw_value> parameters) {
|
|
query_options options(default_cql_config, db::consistency_level::ONE, std::nullopt, parameters, true,
|
|
query_options::specific_options::DEFAULT);
|
|
return evaluate(e, evaluation_inputs{.options = &options});
|
|
}
|
|
|
|
|
|
// A mock implementation of data_dictionary::database, used in tests
|
|
class mock_database_impl : public data_dictionary::impl {
|
|
schema_ptr _table_schema;
|
|
// we cannot set _table_views here, as _table_schema is not necessarily
|
|
// a view. but if a test calls get_table_views(), the test guarantees
|
|
// that the _table_schema is a view, so we set _table_views is the accsseor
|
|
// instead.
|
|
mutable std::vector<view_ptr> _table_views;
|
|
::lw_shared_ptr<data_dictionary::keyspace_metadata> _keyspace_metadata;
|
|
|
|
db::config _config;
|
|
|
|
public:
|
|
explicit mock_database_impl(schema_ptr table_schema)
|
|
: _table_schema(table_schema),
|
|
_keyspace_metadata(make_lw_shared<data_dictionary::keyspace_metadata>(_table_schema->ks_name(),
|
|
"MockReplicationStrategy",
|
|
locator::replication_strategy_config_options{},
|
|
std::nullopt,
|
|
false,
|
|
std::vector<schema_ptr>({_table_schema}))) {}
|
|
|
|
static std::pair<data_dictionary::database, std::unique_ptr<mock_database_impl>> make(schema_ptr table_schema) {
|
|
std::unique_ptr<mock_database_impl> mock_db = std::make_unique<mock_database_impl>(table_schema);
|
|
data_dictionary::database db = make_database(mock_db.get(), nullptr);
|
|
return std::pair(std::move(db), std::move(mock_db));
|
|
}
|
|
|
|
virtual const table_schema_version& get_version(data_dictionary::database db) const override {
|
|
throw std::bad_function_call();
|
|
}
|
|
|
|
virtual std::optional<data_dictionary::keyspace> try_find_keyspace(data_dictionary::database db,
|
|
std::string_view name) const override {
|
|
if (_table_schema->ks_name() == name) {
|
|
return make_keyspace(this, nullptr);
|
|
}
|
|
return std::nullopt;
|
|
}
|
|
virtual std::vector<data_dictionary::keyspace> get_keyspaces(data_dictionary::database db) const override {
|
|
return {make_keyspace(this, nullptr)};
|
|
}
|
|
virtual std::vector<sstring> get_user_keyspaces(data_dictionary::database db) const override {
|
|
return {_table_schema->ks_name()};
|
|
}
|
|
virtual std::vector<sstring> get_all_keyspaces(data_dictionary::database db) const override {
|
|
return {_table_schema->ks_name()};
|
|
}
|
|
virtual std::vector<data_dictionary::table> get_tables(data_dictionary::database db) const override {
|
|
return {make_table(this, nullptr)};
|
|
}
|
|
virtual std::optional<data_dictionary::table> try_find_table(data_dictionary::database db,
|
|
std::string_view ks,
|
|
std::string_view tab) const override {
|
|
if (_table_schema->ks_name() == ks && _table_schema->cf_name() == tab) {
|
|
return make_table(this, nullptr);
|
|
}
|
|
return std::nullopt;
|
|
}
|
|
virtual std::optional<data_dictionary::table> try_find_table(data_dictionary::database db,
|
|
table_id id) const override {
|
|
if (_table_schema->id() == id) {
|
|
return make_table(this, nullptr);
|
|
}
|
|
return std::nullopt;
|
|
}
|
|
virtual const secondary_index::secondary_index_manager& get_index_manager(data_dictionary::table t) const override {
|
|
throw std::bad_function_call();
|
|
}
|
|
virtual schema_ptr get_table_schema(data_dictionary::table t) const override { return _table_schema; }
|
|
virtual lw_shared_ptr<data_dictionary::keyspace_metadata> get_keyspace_metadata(
|
|
data_dictionary::keyspace ks) const override {
|
|
return _keyspace_metadata;
|
|
}
|
|
|
|
virtual bool is_internal(data_dictionary::keyspace ks) const override { return false; }
|
|
virtual const locator::abstract_replication_strategy& get_replication_strategy(
|
|
data_dictionary::keyspace ks) const override {
|
|
throw std::bad_function_call();
|
|
}
|
|
virtual const std::vector<view_ptr>& get_table_views(data_dictionary::table t) const override {
|
|
_table_views = std::vector{view_ptr(_table_schema)};
|
|
return _table_views;
|
|
}
|
|
virtual sstring get_available_index_name(data_dictionary::database db,
|
|
std::string_view ks_name,
|
|
std::string_view table_name,
|
|
std::optional<sstring> index_name_root) const override {
|
|
return {};
|
|
}
|
|
virtual std::set<sstring> existing_index_names(data_dictionary::database db,
|
|
std::string_view ks_name,
|
|
std::string_view cf_to_exclude = {}) const override {
|
|
return {};
|
|
}
|
|
virtual schema_ptr find_indexed_table(data_dictionary::database db,
|
|
std::string_view ks_name,
|
|
std::string_view index_name) const override {
|
|
return nullptr;
|
|
}
|
|
virtual schema_ptr get_cdc_base_table(data_dictionary::database db, const schema&) const override {
|
|
return nullptr;
|
|
}
|
|
virtual const db::config& get_config(data_dictionary::database db) const override { return _config; }
|
|
virtual const db::extensions& get_extensions(data_dictionary::database db) const override {
|
|
return _config.extensions();
|
|
}
|
|
virtual const gms::feature_service& get_features(data_dictionary::database db) const override {
|
|
throw std::bad_function_call();
|
|
}
|
|
virtual replica::database& real_database(data_dictionary::database db) const override {
|
|
throw std::bad_function_call();
|
|
}
|
|
virtual replica::database* real_database_ptr(data_dictionary::database db) const override {
|
|
return nullptr;
|
|
}
|
|
|
|
virtual ~mock_database_impl() = default;
|
|
};
|
|
|
|
std::pair<data_dictionary::database, std::unique_ptr<data_dictionary::impl>> make_data_dictionary_database(
|
|
const schema_ptr& table_schema) {
|
|
return mock_database_impl::make(table_schema);
|
|
}
|
|
} // namespace test_utils
|
|
} // namespace expr
|
|
} // namespace cql3
|