From 10e241988e7673217b1e945be0eb476ae8bf0b70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Radwa=C5=84ski?= Date: Thu, 21 Apr 2022 14:43:17 +0200 Subject: [PATCH] cql/expr/expression, index/secondary_index_manager: needs_filtering and index_supports_expression rewrite to accomodate for indexes over collections --- cql3/expr/expression.cc | 64 +++++++++++++++++++++----------- index/secondary_index_manager.cc | 27 +++++++------- index/secondary_index_manager.hh | 23 +++++++++++- 3 files changed, 78 insertions(+), 36 deletions(-) diff --git a/cql3/expr/expression.cc b/cql3/expr/expression.cc index 47245968a5..1b8ebb89d1 100644 --- a/cql3/expr/expression.cc +++ b/cql3/expr/expression.cc @@ -1005,11 +1005,26 @@ nonwrapping_range 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, diff --git a/index/secondary_index_manager.cc b/index/secondary_index_manager.cc index 86ba7ffb92..076ac53370 100644 --- a/index/secondary_index_manager.cc +++ b/index/secondary_index_manager.cc @@ -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 { diff --git a/index/secondary_index_manager.hh b/index/secondary_index_manager.hh index af3c608dd3..6598eac8e5 100644 --- a/index/secondary_index_manager.hh +++ b/index/secondary_index_manager.hh @@ -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;