cql3: expr: Add evaluate_IN_list

A list representing IN values might contain NULLs before evaluation.
We can remove them during evaluation, because nothing equals NULL.
If we don't remove them, there are gonna be errors, because a list can't contain NULLs.

Signed-off-by: Jan Ciolek <jan.ciolek@scylladb.com>
This commit is contained in:
Jan Ciolek
2021-09-08 14:08:05 +02:00
parent 5a90fd097a
commit 25caa1950d
4 changed files with 65 additions and 0 deletions

View File

@@ -1364,6 +1364,43 @@ constant evaluate(term& term_ref, const query_options& options) {
return evaluate(&term_ref, options);
}
constant evaluate_IN_list(term* term_ptr, const query_options& options) {
if (term_ptr == nullptr) {
return constant::make_null();
}
::shared_ptr<terminal> bound;
lists::delayed_value* delayed_list = dynamic_cast<lists::delayed_value*>(term_ptr);
if (delayed_list != nullptr) {
bound = delayed_list->bind_ignore_null(options);
} else {
bound = term_ptr->bind(options);
}
if (bound.get() == nullptr) {
return constant::make_null();
}
lists::value* list_value = dynamic_cast<lists::value*>(bound.get());
if (list_value != nullptr) {
// Remove NULL elements from the list
std::remove_if(list_value->_elements.begin(), list_value->_elements.end(),
[](const managed_bytes_opt& element) { return !element.has_value(); });
}
raw_value raw_val = bound->get(options);
data_type val_type = bound->get_value_type();
return constant(std::move(raw_val), std::move(val_type));
}
constant evaluate_IN_list(const ::shared_ptr<term>& term_ptr, const query_options& options) {
return evaluate_IN_list(term_ptr.get(), options);
}
constant evaluate_IN_list(term& term_ref, const query_options& options) {
return evaluate_IN_list(&term_ref, options);
}
cql3::raw_value_view evaluate_to_raw_view(const ::shared_ptr<term>& term_ptr, const query_options& options) {
constant value = evaluate(term_ptr, options);
return cql3::raw_value_view::make_temporary(std::move(value.value));

View File

@@ -546,6 +546,12 @@ constant evaluate(const ::shared_ptr<term>&, const query_options&);
constant evaluate(term*, const query_options&);
constant evaluate(term&, const query_options&);
// Similar to evaluate(), but ignores any NULL values in the final list value.
// In an IN restriction nulls can be ignored, because nothing equals NULL.
constant evaluate_IN_list(const ::shared_ptr<term>&, const query_options&);
constant evaluate_IN_list(term*, const query_options&);
constant evaluate_IN_list(term&, const query_options&);
// Calls evaluate() on the term and then converts the constant to raw_value_view
cql3::raw_value_view evaluate_to_raw_view(const ::shared_ptr<term>&, const query_options&);
cql3::raw_value_view evaluate_to_raw_view(term&, const query_options&);

View File

@@ -149,6 +149,25 @@ lists::delayed_value::bind(const query_options& options) {
return ::make_shared<value>(buffers, _my_type);
}
shared_ptr<terminal>
lists::delayed_value::bind_ignore_null(const query_options& options) {
utils::chunked_vector<managed_bytes_opt> buffers;
buffers.reserve(_elements.size());
for (auto&& t : _elements) {
auto bo = t->bind_and_get(options);
if (bo.is_null()) {
continue;
}
if (bo.is_unset_value()) {
return constants::UNSET_VALUE;
}
buffers.push_back(bo.with_value([] (const FragmentedView auto& v) { return managed_bytes(v); }));
}
return ::make_shared<value>(buffers, _my_type);
}
::shared_ptr<terminal>
lists::marker::bind(const query_options& options) {
const auto& value = options.get_value_at(_bind_index);

View File

@@ -93,6 +93,9 @@ public:
virtual bool contains_bind_marker() const override;
virtual void fill_prepare_context(prepare_context& ctx) const override;
virtual shared_ptr<terminal> bind(const query_options& options) override;
// Binds the value, but skips all nulls inside the list
virtual shared_ptr<terminal> bind_ignore_null(const query_options& options);
const std::vector<shared_ptr<term>>& get_elements() const {
return _elements;
}