cql3: Remove all remaining restrictions code

The classes restriction, restrictions and its children
aren't used anywhere now and can be safely removed.

Some includes need to be modified for the code to compile.

Signed-off-by: Jan Ciolek <jan.ciolek@scylladb.com>
This commit is contained in:
Jan Ciolek
2022-07-18 17:03:51 +02:00
parent bff0b87c18
commit 599bcd6ea7
14 changed files with 5 additions and 1262 deletions

View File

@@ -6,12 +6,10 @@
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
#include "restrictions.hh"
#include "cql3/statements/request_validations.hh"
#include "seastar/util/defer.hh"
#include "cql3/prepare_context.hh"
#include "cql3/restrictions/multi_column_restriction.hh"
#include "cql3/restrictions/token_restriction.hh"
#include "types/list.hh"
namespace cql3 {
namespace expr {

View File

@@ -10,11 +10,11 @@
#pragma once
#include "cql3/restrictions/restriction.hh"
#include <seastar/core/shared_ptr.hh>
#include "to_string.hh"
#include "exceptions/exceptions.hh"
#include "index/secondary_index_manager.hh"
#include "cql3/expr/expression.hh"
namespace cql3 {

View File

@@ -1,443 +0,0 @@
/*
* Copyright (C) 2015-present ScyllaDB
*
* Modified by ScyllaDB
*/
/*
* SPDX-License-Identifier: (AGPL-3.0-or-later and Apache-2.0)
*/
#pragma once
#include "cql3/statements/request_validations.hh"
#include "cql3/restrictions/primary_key_restrictions.hh"
#include "cql3/statements/request_validations.hh"
#include "cql3/restrictions/single_column_primary_key_restrictions.hh"
#include "cql3/restrictions/bounds_slice.hh"
#include "cql3/constants.hh"
#include "cql3/lists.hh"
#include "cql3/expr/expression.hh"
#include "types/list.hh"
#include "types/tuple.hh"
namespace cql3 {
namespace restrictions {
inline
expr::tuple_constructor
column_definitions_as_tuple_constructor(const std::vector<const column_definition*>& defs) {
std::vector<expr::expression> columns;
std::vector<data_type> column_types;
columns.reserve(defs.size());
for (auto& def : defs) {
columns.push_back(expr::column_value{def});
column_types.push_back(def->type);
}
data_type ttype = tuple_type_impl::get_instance(std::move(column_types));
return expr::tuple_constructor{std::move(columns), std::move(ttype)};
}
class multi_column_restriction : public clustering_key_restrictions {
private:
bool _has_only_asc_columns;
bool _has_only_desc_columns;
protected:
schema_ptr _schema;
std::vector<const column_definition*> _column_defs;
public:
multi_column_restriction(schema_ptr schema, std::vector<const column_definition*>&& defs)
: _schema(schema)
, _column_defs(std::move(defs))
{
update_asc_desc_existence();
}
virtual std::vector<const column_definition*> get_column_defs() const override {
return _column_defs;
}
virtual void merge_with(::shared_ptr<restriction> other) override {
const auto as_pkr = dynamic_pointer_cast<clustering_key_restrictions>(other);
statements::request_validations::check_true(bool(as_pkr),
"Mixing single column relations and multi column relations on clustering columns is not allowed");
do_merge_with(as_pkr);
update_asc_desc_existence();
expression = make_conjunction(std::move(expression), other->expression);
}
protected:
virtual void do_merge_with(::shared_ptr<clustering_key_restrictions> other) = 0;
/**
* Returns the names of the columns that are specified within this <code>Restrictions</code> and the other one
* as a comma separated <code>String</code>.
*
* @param otherRestrictions the other restrictions
* @return the names of the columns that are specified within this <code>Restrictions</code> and the other one
* as a comma separated <code>String</code>.
*/
sstring get_columns_in_commons(::shared_ptr<restrictions> other) const {
auto ours = get_column_defs();
auto theirs = other->get_column_defs();
std::sort(ours.begin(), ours.end());
std::sort(theirs.begin(), theirs.end());
std::vector<const column_definition*> common;
std::set_intersection(ours.begin(), ours.end(), theirs.begin(), theirs.end(), std::back_inserter(common));
sstring str;
for (auto&& c : common) {
if (!str.empty()) {
str += " ,";
}
str += c->name_as_text();
}
return str;
}
virtual bool has_supporting_index(const secondary_index::secondary_index_manager& index_manager,
expr::allow_local_index allow_local) const override {
for (const auto& index : index_manager.list_indexes()) {
if (!allow_local && index.metadata().local()) {
continue;
}
if (is_supported_by(index))
return true;
}
return false;
}
virtual bool is_supported_by(const secondary_index::index& index) const = 0;
/**
* @return true if the restriction contains at least one column of each
* ordering, false otherwise.
*/
bool is_mixed_order() const {
return !is_desc_order() && !is_asc_order();
}
/**
* @return true if all the restricted columns ordered in descending
* order, false otherwise
*/
bool is_desc_order() const {
return _has_only_desc_columns;
}
/**
* @return true if all the restricted columns ordered in ascending
* order, false otherwise
*/
bool is_asc_order() const {
return _has_only_asc_columns;
}
private:
/**
* Updates the _has_only_asc_columns and _has_only_desc_columns fields.
*/
void update_asc_desc_existence() {
std::size_t num_of_desc =
std::count_if(_column_defs.begin(), _column_defs.end(), [] (const column_definition* cd) { return cd->type->is_reversed(); });
_has_only_asc_columns = num_of_desc == 0;
_has_only_desc_columns = num_of_desc == _column_defs.size();
}
#if 0
/**
* Check if this type of restriction is supported for the specified column by the specified index.
* @param index the Secondary index
*
* @return <code>true</code> this type of restriction is supported by the specified index,
* <code>false</code> otherwise.
*/
protected abstract boolean isSupportedBy(SecondaryIndex index);
#endif
public:
class EQ;
class IN;
class IN_with_values;
class IN_with_marker;
class slice;
};
class multi_column_restriction::EQ final : public multi_column_restriction {
private:
expr::expression _value;
public:
EQ(schema_ptr schema, std::vector<const column_definition*> defs, expr::expression value)
: multi_column_restriction(schema, std::move(defs))
, _value(std::move(value))
{
using namespace expr;
expression = binary_operator{
column_definitions_as_tuple_constructor(_column_defs), oper_t::EQ, _value};
}
virtual bool is_supported_by(const secondary_index::index& index) const override {
for (auto* cdef : _column_defs) {
if (index.supports_expression(*cdef, expr::oper_t::EQ)) {
return true;
}
}
return false;
}
virtual void do_merge_with(::shared_ptr<clustering_key_restrictions> other) override {
throw exceptions::invalid_request_exception(format("{} cannot be restricted by more than one relation if it includes an Equal",
get_columns_in_commons(other)));
}
#if 0
@Override
protected boolean isSupportedBy(SecondaryIndex index)
{
return index.supportsOperator(Operator.EQ);
}
#endif
clustering_key_prefix composite_value(const query_options& options) const {
cql3::raw_value t = expr::evaluate(_value, options);
auto values = expr::get_tuple_elements(t, *type_of(_value));
std::vector<managed_bytes> components;
for (unsigned i = 0; i < values.size(); i++) {
auto component = statements::request_validations::check_not_null(values[i],
"Invalid null value in condition for column {}",
_column_defs.at(i)->name_as_text());
components.emplace_back(*component);
}
return clustering_key_prefix::from_exploded(*_schema, std::move(components));
}
#if 0
@Override
public final void addIndexExpressionTo(List<IndexExpression> expressions,
QueryOptions options) throws InvalidRequestException
{
Tuples.Value t = ((Tuples.Value) value.bind(options));
List<ByteBuffer> values = t.getElements();
for (int i = 0; i < values.size(); i++)
{
ColumnDefinition columnDef = columnDefs.get(i);
ByteBuffer component = validateIndexedValue(columnDef, values.get(i));
expressions.add(new IndexExpression(columnDef.name.bytes, Operator.EQ, component));
}
}
#endif
};
class multi_column_restriction::IN : public multi_column_restriction {
public:
IN(schema_ptr schema, std::vector<const column_definition*> defs)
: multi_column_restriction(schema, std::move(defs))
{ }
virtual bool is_supported_by(const secondary_index::index& index) const override {
for (auto* cdef : _column_defs) {
if (index.supports_expression(*cdef, expr::oper_t::IN)) {
return true;
}
}
return false;
}
#if 0
@Override
public void addIndexExpressionTo(List<IndexExpression> expressions,
QueryOptions options) throws InvalidRequestException
{
List<List<ByteBuffer>> splitInValues = splitValues(options);
checkTrue(splitInValues.size() == 1, "IN restrictions are not supported on indexed columns");
List<ByteBuffer> values = splitInValues.get(0);
checkTrue(values.size() == 1, "IN restrictions are not supported on indexed columns");
ColumnDefinition columnDef = columnDefs.get(0);
ByteBuffer component = validateIndexedValue(columnDef, values.get(0));
expressions.add(new IndexExpression(columnDef.name.bytes, Operator.EQ, component));
}
#endif
virtual void do_merge_with(::shared_ptr<clustering_key_restrictions> other) override {
throw exceptions::invalid_request_exception(format("{} cannot be restricted by more than one relation if it includes a IN",
get_columns_in_commons(other)));
}
#if 0
@Override
protected boolean isSupportedBy(SecondaryIndex index)
{
return index.supportsOperator(Operator.IN);
}
#endif
};
/**
* An IN restriction that has a set of terms for in values.
* For example: "SELECT ... WHERE (a, b, c) IN ((1, 2, 3), (4, 5, 6))" or "WHERE (a, b, c) IN (?, ?)"
*/
class multi_column_restriction::IN_with_values final : public multi_column_restriction::IN {
private:
std::vector<expr::expression> _value;
public:
IN_with_values(schema_ptr schema, std::vector<const column_definition*> defs, std::vector<expr::expression> value)
: multi_column_restriction::IN(schema, std::move(defs))
, _value(std::move(value))
{
std::vector<data_type> column_types;
column_types.reserve(defs.size());
for (const column_definition* cdef : defs) {
column_types.push_back(cdef->type);
}
// type of the delayed_value is frozen list of tuples
data_type list_elements_type = tuple_type_impl::get_instance(std::move(column_types));
data_type in_list_type = list_type_impl::get_instance(std::move(list_elements_type), false);
expr::collection_constructor values_list {
.style = expr::collection_constructor::style_type::list,
.elements = _value,
.type = std::move(in_list_type)
};
using namespace expr;
expression = binary_operator{
column_definitions_as_tuple_constructor(_column_defs),
oper_t::IN,
std::move(values_list)};
}
};
/**
* An IN restriction that uses a single marker for a set of IN values that are tuples.
* For example: "SELECT ... WHERE (a, b, c) IN ?"
*/
class multi_column_restriction::IN_with_marker final : public multi_column_restriction::IN {
private:
expr::bind_variable _marker;
public:
IN_with_marker(schema_ptr schema, std::vector<const column_definition*> defs, expr::bind_variable marker)
: IN(schema, std::move(defs)), _marker(marker) {
using namespace expr;
expression = binary_operator{
column_definitions_as_tuple_constructor(_column_defs),
oper_t::IN,
expr::expression(std::move(marker))};
}
};
class multi_column_restriction::slice final : public multi_column_restriction {
using restriction_shared_ptr = ::shared_ptr<clustering_key_restrictions>;
using mode = expr::comparison_order;
bounds_slice _slice;
mode _mode;
slice(schema_ptr schema, std::vector<const column_definition*> defs, bounds_slice slice, mode m)
: multi_column_restriction(schema, std::move(defs))
, _slice(slice)
, _mode(m)
{ }
public:
slice(schema_ptr schema, std::vector<const column_definition*> defs, statements::bound bound, bool inclusive, expr::expression e, mode m = mode::cql)
: slice(schema, defs, bounds_slice::new_instance(bound, inclusive, e), m)
{
expression = expr::binary_operator{
column_definitions_as_tuple_constructor(defs),
expr::pick_operator(bound, inclusive),
std::move(e),
m};
}
virtual bool is_supported_by(const secondary_index::index& index) const override {
for (auto* cdef : _column_defs) {
if (_slice.is_supported_by(*cdef, index)) {
return true;
}
}
return false;
}
#if 0
@Override
public void addIndexExpressionTo(List<IndexExpression> expressions,
QueryOptions options) throws InvalidRequestException
{
throw invalidRequest("Slice restrictions are not supported on indexed columns which are part of a multi column relation");
}
@Override
protected boolean isSupportedBy(SecondaryIndex index)
{
return slice.isSupportedBy(index);
}
private static Composite.EOC eocFor(Restriction r, Bound eocBound, Bound inclusiveBound)
{
if (eocBound.isStart())
return r.isInclusive(inclusiveBound) ? Composite.EOC.NONE : Composite.EOC.END;
return r.isInclusive(inclusiveBound) ? Composite.EOC.END : Composite.EOC.START;
}
#endif
public:
virtual void do_merge_with(::shared_ptr<clustering_key_restrictions> other) override {
using namespace statements::request_validations;
check_true(has_slice(other->expression),
"Column \"{}\" cannot be restricted by both an equality and an inequality relation",
get_columns_in_commons(other));
auto other_slice = static_pointer_cast<slice>(other);
static auto mode2str = [](auto m) { return m == mode::cql ? "plain" : "SCYLLA_CLUSTERING_BOUND"; };
check_true(other_slice->_mode == this->_mode,
"Invalid combination of restrictions ({} / {})",
mode2str(this->_mode), mode2str(other_slice->_mode)
);
check_false(_slice.has_bound(statements::bound::START) && other_slice->_slice.has_bound(statements::bound::START),
"More than one restriction was found for the start bound on {}",
get_columns_in_commons(other));
check_false(_slice.has_bound(statements::bound::END) && other_slice->_slice.has_bound(statements::bound::END),
"More than one restriction was found for the end bound on {}",
get_columns_in_commons(other));
if (_column_defs.size() < other_slice->_column_defs.size()) {
_column_defs = other_slice->_column_defs;
}
_slice.merge(other_slice->_slice);
}
private:
/**
* The function returns the first real inequality component.
* The first real inequality is the index of the first component in the
* tuple that will turn into a slice single column restriction.
* For example: (a, b, c) > (0, 1, 2) and (a, b, c) < (0, 1, 5) will be
* broken into one single column restriction set of the form:
* a = 0 and b = 1 and c > 2 and c < 5 , c is the first element that has
* inequality so for this case the function will return 2.
* @param start_components - the components of the starts tuple range.
* @param end_components - the components of the end tuple range.
* @return an empty value if not found and the index of the first index that
* will yield inequality
*/
std::optional<std::size_t> find_first_neq_component(std::vector<bytes_opt>& start_components,
std::vector<bytes_opt>& end_components) const {
size_t common_components_count = std::min(start_components.size(), end_components.size());
for (size_t i = 0; i < common_components_count ; i++) {
if (start_components[i].value() != end_components[i].value()) {
return i;
}
}
size_t max_components_count = std::max(start_components.size(), end_components.size());
if (common_components_count < max_components_count) {
return common_components_count;
} else {
return std::nullopt;
}
}
};
}
}

View File

@@ -1,144 +0,0 @@
/*
* Copyright (C) 2015-present ScyllaDB
*
* Modified by ScyllaDB
*/
/*
* SPDX-License-Identifier: (AGPL-3.0-or-later and Apache-2.0)
*/
#pragma once
#include <vector>
#include "cql3/query_options.hh"
#include "cql3/statements/bound.hh"
#include "cql3/restrictions/restrictions.hh"
#include "cql3/restrictions/restriction.hh"
#include "cql3/restrictions/restriction.hh"
#include "types.hh"
#include "query-request.hh"
#include <seastar/core/shared_ptr.hh>
namespace cql3 {
namespace restrictions {
/**
* A set of restrictions on a primary key part (partition key or clustering key).
*
* What was in AbstractPrimaryKeyRestrictions was moved here (In pre 1.8 Java interfaces could not have default
* implementations of methods).
*/
class partition_key_restrictions: public restriction, public restrictions, public enable_shared_from_this<partition_key_restrictions> {
public:
partition_key_restrictions() = default;
virtual void merge_with(::shared_ptr<restriction> other) = 0;
virtual ::shared_ptr<partition_key_restrictions> merge_to(schema_ptr, ::shared_ptr<restriction> restriction) {
merge_with(restriction);
return this->shared_from_this();
}
using restrictions::has_supporting_index;
bool empty() const override {
return get_column_defs().empty();
}
uint32_t size() const override {
return uint32_t(get_column_defs().size());
}
bool has_unrestricted_components(const schema& schema) const {
return size() < schema.partition_key_size();
}
virtual bool needs_filtering(const schema& schema) const {
return !empty() && !has_token(expression) &&
(has_unrestricted_components(schema) || has_slice_or_needs_filtering(expression));
}
// NOTICE(sarna): This function is useless for partition key restrictions,
// but it should remain here until single_column_primary_key_restrictions class is detemplatized.
virtual unsigned int num_prefix_columns_that_need_not_be_filtered() const {
return 0;
}
virtual bool is_all_eq() const {
return false;
}
size_t prefix_size(const schema&) const {
return 0;
}
};
class clustering_key_restrictions : public restriction, public restrictions, public enable_shared_from_this<clustering_key_restrictions> {
public:
clustering_key_restrictions() = default;
virtual void merge_with(::shared_ptr<restriction> other) = 0;
virtual ::shared_ptr<clustering_key_restrictions> merge_to(schema_ptr, ::shared_ptr<restriction> restriction) {
merge_with(restriction);
return this->shared_from_this();
}
using restrictions::has_supporting_index;
bool empty() const override {
return get_column_defs().empty();
}
uint32_t size() const override {
return uint32_t(get_column_defs().size());
}
bool has_unrestricted_components(const schema& schema) const {
return size() < schema.clustering_key_size();
}
virtual bool needs_filtering(const schema& schema) const {
return false;
}
// How long a prefix of the restrictions could have resulted in
// need_filtering() == false. These restrictions do not need to be
// applied during filtering.
// For example, if we have the filter "c1 < 3 and c2 > 3", c1 does
// not need filtering (just a read stopping at c1=3) but c2 does,
// so num_prefix_columns_that_need_not_be_filtered() will be 1.
virtual unsigned int num_prefix_columns_that_need_not_be_filtered() const {
return 0;
}
virtual bool is_all_eq() const {
return false;
}
size_t prefix_size(const schema& schema) const {
size_t count = 0;
if (schema.clustering_key_columns().empty()) {
return count;
}
auto column_defs = get_column_defs();
column_id expected_column_id = schema.clustering_key_columns().begin()->id;
for (auto&& cdef : column_defs) {
if (schema.position(*cdef) != expected_column_id) {
return count;
}
expected_column_id++;
count++;
}
return count;
}
};
// FIXME(sarna): transitive hack only, do not judge. Should be dropped after all primary_key_restrictions<T> uses are removed from code.
template<typename ValueType>
using primary_key_restrictions = std::conditional_t<std::is_same_v<ValueType, partition_key>, partition_key_restrictions, clustering_key_restrictions>;
}
}

View File

@@ -1,32 +0,0 @@
/*
* Copyright (C) 2019-present ScyllaDB
*
* Modified by ScyllaDB
*/
/*
* SPDX-License-Identifier: (AGPL-3.0-or-later and Apache-2.0)
*/
#pragma once
#include "cql3/expr/expression.hh"
namespace cql3 {
namespace restrictions {
/**
* Result of relation::to_restriction(). TODO: remove this class and rewrite to_restriction to return
* expression.
*/
class restriction {
public:
// Init to false for now, to easily detect errors. This whole class is going away.
cql3::expr::expression expression = expr::constant::make_bool(false);
virtual ~restriction() {}
};
}
}

View File

@@ -1,81 +0,0 @@
/*
* Copyright (C) 2015-present ScyllaDB
*
* Modified by ScyllaDB
*/
/*
* SPDX-License-Identifier: (AGPL-3.0-or-later and Apache-2.0)
*/
#pragma once
#include <vector>
#include "cql3/query_options.hh"
#include "types.hh"
#include "schema_fwd.hh"
#include "index/secondary_index_manager.hh"
#include "restriction.hh"
namespace cql3 {
namespace restrictions {
/**
* Sets of restrictions
*/
class restrictions {
public:
virtual ~restrictions() {}
/**
* Returns the column definitions in position order.
* @return the column definitions in position order.
*/
virtual std::vector<const column_definition*> get_column_defs() const = 0;
virtual bytes_opt value_for(const column_definition& cdef, const query_options& options) const {
throw exceptions::invalid_request_exception("Single value can be obtained from single-column restrictions only");
}
/**
* Check if the restriction is on indexed columns.
*
* @param index_manager the index manager
* @return <code>true</code> if the restriction is on indexed columns, <code>false</code>
*/
virtual bool has_supporting_index(const secondary_index::secondary_index_manager& index_manager,
expr::allow_local_index allow_local) const = 0;
#if 0
/**
* Adds to the specified list the <code>index_expression</code>s corresponding to this <code>Restriction</code>.
*
* @param expressions the list to add the <code>index_expression</code>s to
* @param options the query options
* @throws InvalidRequestException if this <code>Restriction</code> cannot be converted into
* <code>index_expression</code>s
*/
virtual void add_index_expression_to(std::vector<::shared_ptr<index_expression>>& expressions,
const query_options& options) = 0;
#endif
/**
* Checks if this <code>SingleColumnprimary_key_restrictions</code> is empty or not.
*
* @return <code>true</code> if this <code>SingleColumnprimary_key_restrictions</code> is empty, <code>false</code> otherwise.
*/
virtual bool empty() const = 0;
/**
* Returns the number of columns that have a restriction.
*
* @return the number of columns that have a restriction.
*/
virtual uint32_t size() const = 0;
};
}
}

View File

@@ -1,270 +0,0 @@
/*
* Copyright (C) 2015-present ScyllaDB
*
* Modified by ScyllaDB
*/
/*
* SPDX-License-Identifier: (AGPL-3.0-or-later and Apache-2.0)
*/
#pragma once
#include <functional>
#include <vector>
#include "schema_fwd.hh"
#include "cartesian_product.hh"
#include "cql3/restrictions/primary_key_restrictions.hh"
#include "cql3/restrictions/single_column_restrictions.hh"
#include "cql3/cql_config.hh"
#include "clustering_bounds_comparator.hh"
#include <boost/range/adaptor/transformed.hpp>
#include <boost/range/adaptor/filtered.hpp>
#include <boost/range/adaptor/map.hpp>
namespace cql3 {
namespace restrictions {
namespace {
template <typename ValueType>
const char*
restricted_component_name_v;
template <>
const char* restricted_component_name_v<partition_key> = "partition key";
template <>
const char* restricted_component_name_v<clustering_key> = "clustering key";
inline
void check_cartesian_product_size(size_t size, size_t max, const char* component_name) {
if (size > max) {
throw std::runtime_error(fmt::format("{} cartesian product size {} is greater than maximum {}",
component_name, size, max));
}
}
}
/**
* A set of single column restrictions on a primary key part (partition key or clustering key).
*/
template<typename ValueType>
class single_column_primary_key_restrictions : public primary_key_restrictions<ValueType> {
using range_type = query::range<ValueType>;
using range_bound = typename range_type::bound;
template<typename OtherValueType>
friend class single_column_primary_key_restrictions;
private:
schema_ptr _schema;
bool _allow_filtering;
::shared_ptr<single_column_restrictions> _restrictions;
private:
static uint32_t max_cartesian_product_size(const restrictions_config& config);
public:
single_column_primary_key_restrictions(schema_ptr schema, bool allow_filtering)
: _schema(schema)
, _allow_filtering(allow_filtering)
, _restrictions(::make_shared<single_column_restrictions>(schema))
{
this->expression = expr::conjunction{}; // This will track _restrictions, which is a conjunction.
}
// Convert another primary key restrictions type into this type, possibly using different schema
template<typename OtherValueType>
explicit single_column_primary_key_restrictions(schema_ptr schema, const single_column_primary_key_restrictions<OtherValueType>& other)
: _schema(schema)
, _allow_filtering(other._allow_filtering)
, _restrictions(::make_shared<single_column_restrictions>(schema))
{
for (const auto& entry : other.restrictions()) {
const column_definition* other_cdef = entry.first;
const column_definition* this_cdef = _schema->get_column_definition(other_cdef->name());
if (!this_cdef) {
throw exceptions::invalid_request_exception(format("Base column {} not found in view index schema", other_cdef->name_as_text()));
}
auto r = ::make_shared<restriction>(*this_cdef);
r->expression = replace_column_def(entry.second->expression, this_cdef);
_restrictions->add_restriction(r);
}
}
virtual bool is_all_eq() const override {
return _restrictions->is_all_eq();
}
void do_merge_with(const ::shared_ptr<restriction>& single_column_restriction) {
if (!_restrictions->empty() && !_allow_filtering) {
auto last_column = *_restrictions->last_column();
auto new_column = *get_the_only_column(single_column_restriction->expression).col;
if (has_slice(this->expression) && _schema->position(new_column) > _schema->position(last_column)) {
throw exceptions::invalid_request_exception(format("Clustering column \"{}\" cannot be restricted (preceding column \"{}\" is restricted by a non-EQ relation)",
new_column.name_as_text(), last_column.name_as_text()));
}
if (_schema->position(new_column) < _schema->position(last_column)) {
if (has_slice(single_column_restriction->expression)) {
throw exceptions::invalid_request_exception(format("PRIMARY KEY column \"{}\" cannot be restricted (preceding column \"{}\" is restricted by a non-EQ relation)",
last_column.name_as_text(), new_column.name_as_text()));
}
}
}
_restrictions->add_restriction(single_column_restriction);
this->expression = make_conjunction(std::move(this->expression), single_column_restriction->expression);
}
virtual void merge_with(::shared_ptr<restriction> restriction) override {
if (find_binop(restriction->expression, [] (const expr::binary_operator& b) {
return expr::is<expr::tuple_constructor>(b.lhs);
})) {
throw exceptions::invalid_request_exception(
"Mixing single column relations and multi column relations on clustering columns is not allowed");
}
if (has_token(restriction->expression)) {
throw exceptions::invalid_request_exception(
format("Columns \"{}\" cannot be restricted by both a normal relation and a token relation",
join(", ", get_column_defs())));
}
do_merge_with(restriction);
}
std::vector<ValueType> values_as_keys(const query_options& options) const {
std::vector<std::vector<managed_bytes_opt>> value_vector;
value_vector.reserve(_restrictions->size());
for (auto&& e : restrictions()) {
auto&& r = e.second;
assert(!has_slice(r->expression));
auto values = expr::as<expr::value_list>(possible_lhs_values(e.first, r->expression, options));
if (values.empty()) {
return {};
}
value_vector.emplace_back(std::make_move_iterator(values.begin()), std::make_move_iterator(values.end()));
}
std::vector<ValueType> result;
auto size = cartesian_product_size(value_vector);
check_cartesian_product_size(size, max_cartesian_product_size(options.get_cql_config().restrictions),
restricted_component_name_v<ValueType>);
result.reserve(size);
for (auto&& v : make_cartesian_product(value_vector)) {
result.emplace_back(ValueType::from_optional_exploded(*_schema, std::move(v)));
}
return result;
}
public:
std::vector<bytes_opt> values(const query_options& options) const {
auto src = values_as_keys(options);
std::vector<bytes_opt> res;
for (const ValueType& r : src) {
for (const auto& component : r.components()) {
res.emplace_back(to_bytes(component));
}
}
return res;
}
virtual bytes_opt value_for(const column_definition& cdef, const query_options& options) const override {
return _restrictions->value_for(cdef, options);
}
const single_column_restrictions::restrictions_map& restrictions() const {
return _restrictions->restrictions();
}
virtual bool has_supporting_index(const secondary_index::secondary_index_manager& index_manager,
expr::allow_local_index allow_local) const override {
return _restrictions->has_supporting_index(index_manager, allow_local);
}
#if 0
virtual void addIndexExpressionTo(List<IndexExpression> expressions, QueryOptions options) override {
restrictions.addIndexExpressionTo(expressions, options);
}
#endif
virtual std::vector<const column_definition*> get_column_defs() const override {
return _restrictions->get_column_defs();
}
virtual bool empty() const override {
return _restrictions->empty();
}
virtual uint32_t size() const override {
return _restrictions->size();
}
virtual bool needs_filtering(const schema& schema) const override;
virtual unsigned int num_prefix_columns_that_need_not_be_filtered() const override;
};
template<>
inline bool single_column_primary_key_restrictions<partition_key>::needs_filtering(const schema& schema) const {
return primary_key_restrictions<partition_key>::needs_filtering(schema);
}
// How many of the restrictions (in column order) do not need filtering
// because they are implemented as a slice (potentially, a contiguous disk
// read). For example, if we have the filter "c1 < 3 and c2 > 3", c1 does not
// need filtering but c2 does so num_prefix_columns_that_need_not_be_filtered
// will be 1.
template<>
inline unsigned single_column_primary_key_restrictions<clustering_key>::num_prefix_columns_that_need_not_be_filtered() const {
// Restrictions currently need filtering in three cases:
// 1. any of them is a CONTAINS restriction
// 2. restrictions do not form a contiguous prefix (i.e. there are gaps in it)
// 3. a SLICE restriction isn't on a last place
column_id position = 0;
unsigned int count = 0;
for (const auto& restriction : restrictions() | boost::adaptors::map_values) {
if (find_needs_filtering(restriction->expression)
|| position != get_the_only_column(restriction->expression).col->id) {
return count;
}
if (!has_slice(restriction->expression)) {
position = get_the_only_column(restriction->expression).col->id + 1;
}
count++;
}
return count;
}
template<>
inline bool single_column_primary_key_restrictions<clustering_key>::needs_filtering(const schema&) const {
return num_prefix_columns_that_need_not_be_filtered() < size();
}
template<>
inline unsigned single_column_primary_key_restrictions<partition_key>::num_prefix_columns_that_need_not_be_filtered() const {
// skip_filtering() is currently called only for clustering key
// restrictions, so it doesn't matter what we return here.
return 0;
}
//TODO(sarna): These should be transformed into actual class definitions after detemplatizing single_column_primary_key_restrictions<T>
using single_column_partition_key_restrictions = single_column_primary_key_restrictions<partition_key>;
using single_column_clustering_key_restrictions = single_column_primary_key_restrictions<clustering_key>;
template <>
inline
uint32_t single_column_primary_key_restrictions<partition_key>::max_cartesian_product_size(const restrictions_config& config) {
return config.partition_key_restrictions_max_cartesian_product_size;
}
template <>
inline
uint32_t single_column_primary_key_restrictions<clustering_key>::max_cartesian_product_size(const restrictions_config& config) {
return config.clustering_key_restrictions_max_cartesian_product_size;
}
}
}

View File

@@ -1,212 +0,0 @@
/*
* Copyright (C) 2015-present ScyllaDB
*
* Modified by ScyllaDB
*/
/*
* SPDX-License-Identifier: (AGPL-3.0-or-later and Apache-2.0)
*/
#pragma once
#include "cql3/restrictions/restrictions.hh"
#include "schema_fwd.hh"
#include "types.hh"
namespace cql3 {
namespace restrictions {
/**
* Sets of single column _restrictions.
*/
class single_column_restrictions : public restrictions {
private:
/**
* The comparator used to sort the <code>restriction</code>s.
*/
struct column_definition_comparator {
schema_ptr _schema;
bool operator()(const column_definition* def1, const column_definition* def2) const {
auto pos1 = _schema->position(*def1);
auto pos2 = _schema->position(*def2);
if (pos1 != pos2) {
return pos1 < pos2;
}
// FIXME: shouldn't we use regular column name comparator here? Origin does not...
return less_unsigned(def1->name(), def2->name());
}
};
/**
* The _restrictions per column.
*/
public:
using restrictions_map = std::map<const column_definition*, ::shared_ptr<restriction>, column_definition_comparator>;
private:
restrictions_map _restrictions;
bool _is_all_eq = true;
public:
single_column_restrictions(schema_ptr schema)
: _restrictions(column_definition_comparator{std::move(schema)})
{ }
#if 0
@Override
public final void addIndexExpressionTo(List<IndexExpression> expressions,
QueryOptions options) throws InvalidRequestException
{
for (Restriction restriction : _restrictions.values())
restriction.addIndexExpressionTo(expressions, options);
}
#endif
virtual std::vector<const column_definition*> get_column_defs() const override {
std::vector<const column_definition*> r;
for (auto&& e : _restrictions) {
r.push_back(e.first);
}
return r;
}
virtual bytes_opt value_for(const column_definition& cdef, const query_options& options) const override {
auto it = _restrictions.find(std::addressof(cdef));
if (it == _restrictions.end()) {
return bytes_opt{};
} else {
const auto values = std::get<expr::value_list>(possible_lhs_values(&cdef, it->second->expression, options));
if (values.empty()) {
return bytes_opt{};
}
assert(values.size() == 1);
return to_bytes(values.front());
}
}
/**
* Returns the restriction associated to the specified column.
*
* @param column_def the column definition
* @return the restriction associated to the specified column
*/
::shared_ptr<restriction> get_restriction(const column_definition& column_def) const {
auto i = _restrictions.find(&column_def);
if (i == _restrictions.end()) {
return {};
}
return i->second;
}
virtual bool empty() const override {
return _restrictions.empty();
}
virtual uint32_t size() const override {
return _restrictions.size();
}
/**
* Adds the specified restriction to this set of _restrictions.
*
* @param restriction the restriction to add
* @throws InvalidRequestException if the new restriction cannot be added
*/
void add_restriction(::shared_ptr<restriction> restriction) {
if (!find(restriction->expression, expr::oper_t::EQ)) {
_is_all_eq = false;
}
auto i = _restrictions.find(get_the_only_column(restriction->expression).col);
if (i == _restrictions.end()) {
_restrictions.emplace_hint(i, get_the_only_column(restriction->expression).col, std::move(restriction));
} else {
auto& e = i->second->expression;
e = make_conjunction(std::move(e), restriction->expression);
}
}
virtual bool has_supporting_index(const secondary_index::secondary_index_manager& index_manager,
expr::allow_local_index allow_local) const override {
for (auto&& e : _restrictions) {
if (expr::has_supporting_index(e.second->expression, index_manager, allow_local)) {
return true;
}
}
return false;
}
/**
* Returns the column after the specified one.
*
* @param column_def the column for which the next one need to be found
* @return the column after the specified one.
*/
const column_definition* next_column(const column_definition& column_def) const {
auto i = _restrictions.find(&column_def);
if (i == _restrictions.end()) {
return nullptr;
}
++i;
if (i == _restrictions.end()) {
return nullptr;
}
return i->first;
}
/**
* Returns the definition of the last column.
*
* @return the definition of the last column.
*/
const column_definition* last_column() const {
if (_restrictions.empty()) {
return nullptr;
}
auto i = _restrictions.end();
--i;
return i->first;
}
/**
* Returns the last restriction.
*
* @return the last restriction.
*/
::shared_ptr<restriction> last_restriction() const {
if (_restrictions.empty()) {
return {};
}
auto i = _restrictions.end();
--i;
return i->second;
}
const restrictions_map& restrictions() const {
return _restrictions;
}
/**
* Checks if the _restrictions contains multiple contains, contains key, or map[key] = value.
*
* @return <code>true</code> if the _restrictions contains multiple contains, contains key, or ,
* map[key] = value; <code>false</code> otherwise
*/
bool has_multiple_contains() const {
uint32_t number_of_contains = 0;
for (auto&& e : _restrictions) {
number_of_contains += count_if(e.second->expression, expr::is_on_collection);
if (number_of_contains > 1) {
return true;
}
}
return number_of_contains > 1;
}
bool is_all_eq() const {
return _is_all_eq;
}
};
}
}

View File

@@ -19,10 +19,9 @@
#include "cql3/expr/expression.hh"
#include "query-result-reader.hh"
#include "statement_restrictions.hh"
#include "multi_column_restriction.hh"
#include "token_restriction.hh"
#include "data_dictionary/data_dictionary.hh"
#include "cartesian_product.hh"
#include "cql3/cql_config.hh"
#include "cql3/constants.hh"
#include "cql3/lists.hh"
@@ -31,7 +30,6 @@
#include "types/list.hh"
#include "types/map.hh"
#include "types/set.hh"
#include "cql3/expr/restrictions.hh"
namespace cql3 {
namespace restrictions {

View File

@@ -14,13 +14,12 @@
#include <list>
#include "bounds_slice.hh"
#include "cql3/expr/expression.hh"
#include "cql3/expr/restrictions.hh"
#include "to_string.hh"
#include "schema_fwd.hh"
#include "cql3/restrictions/restrictions.hh"
#include "cql3/restrictions/primary_key_restrictions.hh"
#include "cql3/restrictions/single_column_restrictions.hh"
#include "cql3/prepare_context.hh"
#include "cql3/statements/statement_type.hh"
#include "query-request.hh"
namespace cql3 {

View File

@@ -1,67 +0,0 @@
/*
* Copyright (C) 2015-present ScyllaDB
*
* Modified by ScyllaDB
*/
/*
* SPDX-License-Identifier: (AGPL-3.0-or-later and Apache-2.0)
*/
#pragma once
#include "restriction.hh"
#include "primary_key_restrictions.hh"
#include "exceptions/exceptions.hh"
#include "bounds_slice.hh"
#include "keys.hh"
class column_definition;
namespace cql3 {
namespace restrictions {
/**
* <code>Restriction</code> using the token function.
*/
class token_restriction: public partition_key_restrictions {
private:
/**
* The definition of the columns to which apply the token restriction.
*/
std::vector<const column_definition *> _column_definitions;
public:
token_restriction(std::vector<const column_definition *> c)
: _column_definitions(std::move(c)) {
}
std::vector<const column_definition*> get_column_defs() const override {
return _column_definitions;
}
void merge_with(::shared_ptr<restriction> restriction) override {
if (!has_token(restriction->expression)) {
throw exceptions::invalid_request_exception(
format("Columns \"{}\" cannot be restricted by both a normal relation and a token relation",
join(", ", get_column_defs())));
}
expression = make_conjunction(std::move(expression), restriction->expression);
}
virtual bool has_supporting_index(const secondary_index::secondary_index_manager& index_manager,
expr::allow_local_index allow_local) const override {
return false;
}
#if 0
void add_index_expression_to(std::vector<::shared_ptr<index_expression>>& expressions,
const query_options& options) override {
throw exceptions::unsupported_operation_exception();
}
#endif
};
}
}

View File

@@ -18,7 +18,6 @@
#include "cql3/selection/selector_factories.hh"
#include "cql3/result_set.hh"
#include "cql3/query_options.hh"
#include "cql3/restrictions/multi_column_restriction.hh"
#include "cql3/restrictions/statement_restrictions.hh"
namespace cql3 {

View File

@@ -18,7 +18,6 @@
#include "cql3/functions/as_json_function.hh"
#include "cql3/selection/selection.hh"
#include "cql3/util.hh"
#include "cql3/restrictions/single_column_primary_key_restrictions.hh"
#include "cql3/restrictions/statement_restrictions.hh"
#include "cql3/selection/selector_factories.hh"
#include "validation.hh"

View File

@@ -15,7 +15,6 @@
#include "cql3/util.hh"
#include "test/lib/cql_assertions.hh"
#include "test/lib/cql_test_env.hh"
#include "cql3/restrictions/multi_column_restriction.hh"
using namespace cql3;