cql/expr/expression, index/secondary_index_manager: needs_filtering and

index_supports_expression rewrite to accomodate for indexes over
collections
This commit is contained in:
Michał Radwański
2022-04-21 14:43:17 +02:00
committed by Nadav Har'El
parent ac97086855
commit 10e241988e
3 changed files with 78 additions and 36 deletions

View File

@@ -1005,11 +1005,26 @@ nonwrapping_range<managed_bytes> to_range(const value_set& s) {
}, s);
}
bool is_supported_by(const expression& expr, const secondary_index::index& idx) {
using std::placeholders::_1;
namespace {
constexpr inline secondary_index::index::supports_expression_v operator&&(secondary_index::index::supports_expression_v v1, secondary_index::index::supports_expression_v v2) {
using namespace secondary_index;
auto True = index::supports_expression_v::from_bool(true);
return v1 == True && v2 == True ? True : index::supports_expression_v::from_bool(false);
}
secondary_index::index::supports_expression_v is_supported_by_helper(const expression& expr, const secondary_index::index& idx) {
using ret_t = secondary_index::index::supports_expression_v;
using namespace secondary_index;
return expr::visit(overloaded_functor{
[&] (const conjunction& conj) {
return boost::algorithm::all_of(conj.children, std::bind(is_supported_by, _1, idx));
[&] (const conjunction& conj) -> ret_t {
if (conj.children.empty()) {
return index::supports_expression_v::from_bool(true);
}
auto init = is_supported_by_helper(conj.children[0], idx);
return std::accumulate(std::begin(conj.children) + 1, std::end(conj.children), init,
[&] (ret_t acc, const expression& child) -> ret_t {
return acc && is_supported_by_helper(child, idx);
});
},
[&] (const binary_operator& oper) {
return expr::visit(overloaded_functor{
@@ -1023,57 +1038,64 @@ bool is_supported_by(const expression& expr, const secondary_index::index& idx)
}
}
// We don't use index table for multi-column restrictions, as it cannot avoid filtering.
return false;
return index::supports_expression_v::from_bool(false);
},
[&] (const token&) { return false; },
[&] (const subscript& s) -> bool {
[&] (const token&) { return index::supports_expression_v::from_bool(false); },
[&] (const subscript& s) -> ret_t {
const column_value& col = get_subscripted_column(s);
return idx.supports_subscript_expression(*col.col, oper.op);
},
[&] (const binary_operator&) -> bool {
[&] (const binary_operator&) -> ret_t {
on_internal_error(expr_logger, "is_supported_by: nested binary operators are not supported");
},
[&] (const conjunction&) -> bool {
[&] (const conjunction&) -> ret_t {
on_internal_error(expr_logger, "is_supported_by: conjunctions are not supported as the LHS of a binary expression");
},
[] (const constant&) -> bool {
[] (const constant&) -> ret_t {
on_internal_error(expr_logger, "is_supported_by: constants are not supported as the LHS of a binary expression");
},
[] (const unresolved_identifier&) -> bool {
[] (const unresolved_identifier&) -> ret_t {
on_internal_error(expr_logger, "is_supported_by: an unresolved identifier is not supported as the LHS of a binary expression");
},
[&] (const column_mutation_attribute&) -> bool {
[&] (const column_mutation_attribute&) -> ret_t {
on_internal_error(expr_logger, "is_supported_by: writetime/ttl are not supported as the LHS of a binary expression");
},
[&] (const function_call&) -> bool {
[&] (const function_call&) -> ret_t {
on_internal_error(expr_logger, "is_supported_by: function calls are not supported as the LHS of a binary expression");
},
[&] (const cast&) -> bool {
[&] (const cast&) -> ret_t {
on_internal_error(expr_logger, "is_supported_by: typecasts are not supported as the LHS of a binary expression");
},
[&] (const field_selection&) -> bool {
[&] (const field_selection&) -> ret_t {
on_internal_error(expr_logger, "is_supported_by: field selections are not supported as the LHS of a binary expression");
},
[&] (const null&) -> bool {
[&] (const null&) -> ret_t {
on_internal_error(expr_logger, "is_supported_by: nulls are not supported as the LHS of a binary expression");
},
[&] (const bind_variable&) -> bool {
[&] (const bind_variable&) -> ret_t {
on_internal_error(expr_logger, "is_supported_by: bind variables are not supported as the LHS of a binary expression");
},
[&] (const untyped_constant&) -> bool {
[&] (const untyped_constant&) -> ret_t {
on_internal_error(expr_logger, "is_supported_by: untyped constants are not supported as the LHS of a binary expression");
},
[&] (const collection_constructor&) -> bool {
[&] (const collection_constructor&) -> ret_t {
on_internal_error(expr_logger, "is_supported_by: collection constructors are not supported as the LHS of a binary expression");
},
[&] (const usertype_constructor&) -> bool {
[&] (const usertype_constructor&) -> ret_t {
on_internal_error(expr_logger, "is_supported_by: user type constructors are not supported as the LHS of a binary expression");
},
}, oper.lhs);
},
[] (const auto& default_case) { return false; }
[] (const auto& default_case) { return index::supports_expression_v::from_bool(false); }
}, expr);
}
}
bool is_supported_by(const expression& expr, const secondary_index::index& idx) {
auto s = is_supported_by_helper(expr, idx);
return s != secondary_index::index::supports_expression_v::from_bool(false);
}
bool has_supporting_index(
const expression& expr,

View File

@@ -38,43 +38,44 @@ bool index::depends_on(const column_definition& cdef) const {
return cdef.name_as_text() == _target_column;
}
bool index::supports_expression(const column_definition& cdef, const cql3::expr::oper_t op) const {
index::supports_expression_v index::supports_expression(const column_definition& cdef, const cql3::expr::oper_t op) const {
using target_type = cql3::statements::index_target::target_type;
auto collection_yes = supports_expression_v::from_bool_collection(true);
if (cdef.name_as_text() != _target_column) {
return false;
return supports_expression_v::from_bool(false);
}
switch (op) {
case cql3::expr::oper_t::EQ:
return _target_type == target_type::regular_values;
return supports_expression_v::from_bool(_target_type == target_type::regular_values);
case cql3::expr::oper_t::CONTAINS:
if (cdef.type->is_set() && _target_type == target_type::keys) {
return true;
return collection_yes;
}
if (cdef.type->is_list() && _target_type == target_type::collection_values) {
return true;
return collection_yes;
}
if (cdef.type->is_map() && _target_type == target_type::collection_values) {
return true;
return collection_yes;
}
return false;
return supports_expression_v::from_bool(false);
case cql3::expr::oper_t::CONTAINS_KEY:
if (cdef.type->is_map() && _target_type == target_type::keys) {
return true;
return collection_yes;
}
return false;
return supports_expression_v::from_bool(false);
default:
return false;
return supports_expression_v::from_bool(false);
}
}
bool index::supports_subscript_expression(const column_definition& cdef, const cql3::expr::oper_t op) const {
index::supports_expression_v index::supports_subscript_expression(const column_definition& cdef, const cql3::expr::oper_t op) const {
using target_type = cql3::statements::index_target::target_type;
if (cdef.name_as_text() != _target_column) {
return false;
return supports_expression_v::from_bool(false);
}
return op == cql3::expr::oper_t::EQ && _target_type == target_type::keys_and_values;
return supports_expression_v::from_bool_collection(op == cql3::expr::oper_t::EQ && _target_type == target_type::keys_and_values);
}
const index_metadata& index::metadata() const {

View File

@@ -42,8 +42,27 @@ class index {
public:
index(const sstring& target_column, const index_metadata& im);
bool depends_on(const column_definition& cdef) const;
bool supports_expression(const column_definition& cdef, const cql3::expr::oper_t op) const;
bool supports_subscript_expression(const column_definition& cdef, const cql3::expr::oper_t op) const;
struct supports_expression_v {
enum class value_type {
UsualYes,
CollectionYes,
No,
};
value_type value;
operator bool() const {
return value != value_type::No;
}
static constexpr supports_expression_v from_bool(bool b) {
return {b ? value_type::UsualYes : value_type::No};
}
static constexpr supports_expression_v from_bool_collection(bool b) {
return {b ? value_type::CollectionYes : value_type::No};
}
friend bool operator==(supports_expression_v, supports_expression_v) = default;
};
supports_expression_v supports_expression(const column_definition& cdef, const cql3::expr::oper_t op) const;
supports_expression_v supports_subscript_expression(const column_definition& cdef, const cql3::expr::oper_t op) const;
const index_metadata& metadata() const;
const sstring& target_column() const {
return _target_column;