43 changes: 24 additions & 19 deletions cql3/restrictions/multi_column_restriction.hh
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@

#pragma once

#include "cql3/tuples.hh"
#include "cql3/statements/request_validations.hh"
#include "cql3/restrictions/primary_key_restrictions.hh"
#include "cql3/statements/request_validations.hh"
Expand All @@ -50,6 +49,7 @@
#include "cql3/lists.hh"
#include "cql3/expr/expression.hh"
#include "types/list.hh"
#include "types/tuple.hh"

namespace cql3 {

Expand Down Expand Up @@ -196,9 +196,9 @@ public:

class multi_column_restriction::EQ final : public multi_column_restriction {
private:
::shared_ptr<term> _value;
expr::expression _value;
public:
EQ(schema_ptr schema, std::vector<const column_definition*> defs, ::shared_ptr<term> value)
EQ(schema_ptr schema, std::vector<const column_definition*> defs, expr::expression value)
: multi_column_restriction(schema, std::move(defs))
, _value(std::move(value))
{
Expand Down Expand Up @@ -309,11 +309,11 @@ public:
*/
class multi_column_restriction::IN_with_values final : public multi_column_restriction::IN {
private:
std::vector<::shared_ptr<term>> _values;
std::vector<expr::expression> _value;
public:
IN_with_values(schema_ptr schema, std::vector<const column_definition*> defs, std::vector<::shared_ptr<term>> value)
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))
, _values(std::move(value))
, _value(std::move(value))
{
std::vector<data_type> column_types;
column_types.reserve(defs.size());
Expand All @@ -325,11 +325,17 @@ public:
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,
::make_shared<lists::delayed_value>(_values, std::move(in_list_type))};
std::move(values_list)};
}
};

Expand All @@ -340,37 +346,37 @@ public:
*/
class multi_column_restriction::IN_with_marker final : public multi_column_restriction::IN {
private:
shared_ptr<abstract_marker> _marker;
expr::bind_variable _marker;
public:
IN_with_marker(schema_ptr schema, std::vector<const column_definition*> defs, shared_ptr<abstract_marker> marker)
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,
std::move(marker)};
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;
term_slice _slice;
bounds_slice _slice;
mode _mode;

slice(schema_ptr schema, std::vector<const column_definition*> defs, term_slice slice, mode m)
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, shared_ptr<term> term, mode m = mode::cql)
: slice(schema, defs, term_slice::new_instance(bound, inclusive, term), m)
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(term),
std::move(e),
m};
}

Expand Down Expand Up @@ -472,17 +478,16 @@ private:
*/
::shared_ptr<restriction> make_single_column_restriction(std::optional<cql3::statements::bound> bound, bool inclusive,
std::size_t column_pos, const managed_bytes_opt& value) const {
::shared_ptr<cql3::term> term =
::make_shared<cql3::constants::value>(cql3::raw_value::make_value(value), _column_defs[column_pos]->type);
expr::expression e = expr::constant(cql3::raw_value::make_value(value), _column_defs[column_pos]->type);
using namespace expr;
if (!bound){
auto r = ::make_shared<cql3::restrictions::single_column_restriction>(*_column_defs[column_pos]);
r->expression = binary_operator{column_value{_column_defs[column_pos]}, expr::oper_t::EQ, std::move(term)};
r->expression = binary_operator{column_value{_column_defs[column_pos]}, expr::oper_t::EQ, std::move(e)};
return r;
} else {
auto r = ::make_shared<cql3::restrictions::single_column_restriction>(*_column_defs[column_pos]);
r->expression = binary_operator{
column_value(_column_defs[column_pos]), pick_operator(*bound, inclusive), std::move(term)};
column_value(_column_defs[column_pos]), pick_operator(*bound, inclusive), std::move(e)};
return r;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ public:
}

virtual void merge_with(::shared_ptr<restriction> restriction) override {
if (find_atom(restriction->expression, [] (const expr::binary_operator& b) {
if (find_binop(restriction->expression, [] (const expr::binary_operator& b) {
return expr::is<expr::tuple_constructor>(b.lhs);
})) {
throw exceptions::invalid_request_exception(
Expand Down
3 changes: 1 addition & 2 deletions cql3/restrictions/single_column_restriction.hh
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,7 @@
#include <optional>

#include "cql3/restrictions/restriction.hh"
#include "cql3/restrictions/term_slice.hh"
#include "cql3/term.hh"
#include "cql3/restrictions/bounds_slice.hh"
#include "cql3/abstract_marker.hh"
#include <seastar/core/shared_ptr.hh>
#include "schema_fwd.hh"
Expand Down
26 changes: 12 additions & 14 deletions cql3/restrictions/statement_restrictions.cc
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@
#include "cql3/selection/selection.hh"
#include "cql3/single_column_relation.hh"
#include "cql3/statements/request_validations.hh"
#include "cql3/tuples.hh"
#include "types/list.hh"
#include "types/map.hh"
#include "types/set.hh"
Expand Down Expand Up @@ -452,7 +451,7 @@ statement_restrictions::statement_restrictions(database& db,
const expr::allow_local_index allow_local(
!_partition_key_restrictions->has_unrestricted_components(*_schema)
&& _partition_key_restrictions->is_all_eq());
_has_multi_column = find_atom(_clustering_columns_restrictions->expression, expr::is_multi_column);
_has_multi_column = find_binop(_clustering_columns_restrictions->expression, expr::is_multi_column);
_has_queriable_ck_index = _clustering_columns_restrictions->has_supporting_index(sim, allow_local)
&& !type.is_delete();
_has_queriable_pk_index = _partition_key_restrictions->has_supporting_index(sim, allow_local)
Expand Down Expand Up @@ -499,7 +498,7 @@ statement_restrictions::statement_restrictions(database& db,

if (_uses_secondary_indexing || _clustering_columns_restrictions->needs_filtering(*_schema)) {
_index_restrictions.push_back(_clustering_columns_restrictions);
} else if (find_atom(_clustering_columns_restrictions->expression, expr::is_on_collection)) {
} else if (find_binop(_clustering_columns_restrictions->expression, expr::is_on_collection)) {
fail(unimplemented::cause::INDEXES);
#if 0
_index_restrictions.push_back(new Forwardingprimary_key_restrictions() {
Expand Down Expand Up @@ -689,7 +688,7 @@ void statement_restrictions::process_clustering_columns_restrictions(bool for_vi
return;
}

if (find_atom(_clustering_columns_restrictions->expression, expr::is_on_collection)
if (find_binop(_clustering_columns_restrictions->expression, expr::is_on_collection)
&& !_has_queriable_ck_index && !allow_filtering) {
throw exceptions::invalid_request_exception(
"Cannot restrict clustering columns by a CONTAINS relation without a secondary index or filtering");
Expand Down Expand Up @@ -764,7 +763,7 @@ dht::partition_range_vector partition_ranges_from_singles(
std::vector<std::vector<managed_bytes>> column_values(schema.partition_key_size());
size_t product_size = 1;
for (const auto& e : expressions) {
if (const auto arbitrary_binop = find_atom(e, [] (const binary_operator&) { return true; })) {
if (const auto arbitrary_binop = find_binop(e, [] (const binary_operator&) { return true; })) {
if (auto cv = expr::as_if<expr::column_value>(&arbitrary_binop->lhs)) {
const value_set vals = possible_lhs_values(cv->col, e, options);
if (auto lst = std::get_if<value_list>(&vals)) {
Expand Down Expand Up @@ -1428,7 +1427,7 @@ std::vector<query::clustering_range> statement_restrictions::get_clustering_boun
if (_clustering_prefix_restrictions.empty()) {
return {query::clustering_range::make_open_ended_both_sides()};
}
if (find_atom(_clustering_prefix_restrictions[0], expr::is_multi_column)) {
if (find_binop(_clustering_prefix_restrictions[0], expr::is_multi_column)) {
bool all_natural = true, all_reverse = true; ///< Whether column types are reversed or natural.
for (auto& r : _clustering_prefix_restrictions) { // TODO: move to constructor, do only once.
using namespace expr;
Expand Down Expand Up @@ -1617,7 +1616,7 @@ void statement_restrictions::prepare_indexed_global(const schema& idx_tbl_schema
oper_t::EQ,
// TODO: This should be a unique marker whose value we set at execution time. There is currently no
// handy mechanism for doing that in query_options.
::make_shared<constants::value>(raw_value::make_unset_value(), token_column->type));
expr::constant::make_unset_value(token_column->type));
}

void statement_restrictions::prepare_indexed_local(const schema& idx_tbl_schema) {
Expand Down Expand Up @@ -1647,11 +1646,11 @@ void statement_restrictions::prepare_indexed_local(const schema& idx_tbl_schema)

void statement_restrictions::add_clustering_restrictions_to_idx_ck_prefix(const schema& idx_tbl_schema) {
for (const auto& e : _clustering_prefix_restrictions) {
if (find_atom(_clustering_prefix_restrictions[0], expr::is_multi_column)) {
if (find_binop(_clustering_prefix_restrictions[0], expr::is_multi_column)) {
// TODO: We could handle single-element tuples, eg. `(c)>=(123)`.
break;
}
const auto any_binop = find_atom(e, [] (auto&&) { return true; });
const auto any_binop = find_binop(e, [] (auto&&) { return true; });
if (!any_binop) {
break;
}
Expand Down Expand Up @@ -1689,8 +1688,8 @@ std::vector<query::clustering_range> statement_restrictions::get_global_index_cl
}
// WARNING: We must not yield to another fiber from here until the function's end, lest this RHS be
// overwritten.
const_cast<::shared_ptr<term>&>(expr::as<binary_operator>((*_idx_tbl_ck_prefix)[0]).rhs) =
::make_shared<constants::value>(raw_value::make_value(*token_bytes), token_column.type);
const_cast<expr::expression&>(expr::as<binary_operator>((*_idx_tbl_ck_prefix)[0]).rhs) =
expr::constant(raw_value::make_value(*token_bytes), token_column.type);

// Multi column restrictions are not added to _idx_tbl_ck_prefix, they are handled later by filtering.
return get_single_column_clustering_bounds(options, idx_tbl_schema, *_idx_tbl_ck_prefix);
Expand Down Expand Up @@ -1733,15 +1732,14 @@ sstring statement_restrictions::to_string() const {
}

static bool has_eq_null(const query_options& options, const expression& expr) {
return find_atom(expr, [&] (const binary_operator& binop) {
return binop.op == oper_t::EQ && !evaluate_to_raw_view(binop.rhs, options);
return find_binop(expr, [&] (const binary_operator& binop) {
return binop.op == oper_t::EQ && evaluate(binop.rhs, options).is_null();
});
}

bool statement_restrictions::range_or_slice_eq_null(const query_options& options) const {
return boost::algorithm::any_of(_partition_range_restrictions, std::bind_front(has_eq_null, options))
|| boost::algorithm::any_of(_clustering_prefix_restrictions, std::bind_front(has_eq_null, options));
}

} // namespace restrictions
} // namespace cql3
2 changes: 1 addition & 1 deletion cql3/restrictions/token_restriction.hh
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
#include "restriction.hh"
#include "primary_key_restrictions.hh"
#include "exceptions/exceptions.hh"
#include "term_slice.hh"
#include "bounds_slice.hh"
#include "keys.hh"

class column_definition;
Expand Down
158 changes: 5 additions & 153 deletions cql3/sets.cc
Original file line number Diff line number Diff line change
Expand Up @@ -26,157 +26,9 @@
#include "types/set.hh"

namespace cql3 {

sets::value
sets::value::from_serialized(const raw_value_view& val, const set_type_impl& type, cql_serialization_format sf) {
try {
std::set<managed_bytes, serialized_compare> elements(type.get_elements_type()->as_less_comparator());
if (sf.collection_format_unchanged()) {
utils::chunked_vector<managed_bytes> tmp = val.with_value([sf] (const FragmentedView auto& v) {
return partially_deserialize_listlike(v, sf);
});
for (auto&& element : tmp) {
elements.insert(std::move(element));
}
} else [[unlikely]] {
auto s = val.deserialize<set_type_impl::native_type>(type, sf);
for (auto&& element : s) {
elements.insert(elements.end(), managed_bytes(type.get_elements_type()->decompose(element)));
}
}
return value(std::move(elements), type.shared_from_this());
} catch (marshal_exception& e) {
throw exceptions::invalid_request_exception(e.what());
}
}

cql3::raw_value
sets::value::get(const query_options& options) {
return cql3::raw_value::make_value(get_with_protocol_version(cql_serialization_format::internal()));
}

managed_bytes
sets::value::get_with_protocol_version(cql_serialization_format sf) {
return collection_type_impl::pack_fragmented(_elements.begin(), _elements.end(),
_elements.size(), sf);
}

bool
sets::value::equals(const set_type_impl& st, const value& v) {
if (_elements.size() != v._elements.size()) {
return false;
}
auto&& elements_type = st.get_elements_type();
return std::equal(_elements.begin(), _elements.end(),
v._elements.begin(),
[elements_type] (managed_bytes_view v1, managed_bytes_view v2) {
return elements_type->equal(v1, v2);
});
}

sstring
sets::value::to_string() const {
sstring result = "{";
bool first = true;
for (auto&& e : _elements) {
if (!first) {
result += ", ";
}
first = true;
result += to_hex(e);
}
result += "}";
return result;
}

bool
sets::delayed_value::contains_bind_marker() const {
// False since we don't support them in collection
return false;
}

void
sets::delayed_value::fill_prepare_context(prepare_context& ctx) const {
}

shared_ptr<terminal>
sets::delayed_value::bind(const query_options& options) {
const set_type_impl& my_set_type = dynamic_cast<const set_type_impl&>(_my_type->without_reversed());

std::set<managed_bytes, serialized_compare> buffers(my_set_type.get_elements_type()->as_less_comparator());
for (auto&& t : _elements) {
auto b = expr::evaluate_to_raw_view(t, options);

if (b.is_null()) {
throw exceptions::invalid_request_exception("null is not supported inside collections");
}
if (b.is_unset_value()) {
return constants::UNSET_VALUE;
}
// We don't support value > 64K because the serialization format encode the length as an unsigned short.
if (b.size_bytes() > std::numeric_limits<uint16_t>::max()) {
throw exceptions::invalid_request_exception(format("Set value is too long. Set values are limited to {:d} bytes but {:d} bytes value provided",
std::numeric_limits<uint16_t>::max(),
b.size_bytes()));
}
buffers.insert(buffers.end(), *to_managed_bytes_opt(b));
}
return ::make_shared<value>(std::move(buffers), _my_type);
}

expr::expression sets::delayed_value::to_expression() {
std::vector<expr::expression> new_elements;
new_elements.reserve(_elements.size());

for (shared_ptr<term>& e : _elements) {
new_elements.emplace_back(expr::to_expression(e));
}

return expr::collection_constructor {
.style = expr::collection_constructor::style_type::set,
.elements = std::move(new_elements),
.type = _my_type,
};
}

sets::marker::marker(int32_t bind_index, lw_shared_ptr<column_specification> receiver)
: abstract_marker{bind_index, std::move(receiver)} {
if (!_receiver->type->without_reversed().is_set()) {
throw std::runtime_error(format("Receiver {} for set marker has wrong type: {}",
_receiver->cf_name, _receiver->type->name()));
}
}

::shared_ptr<terminal>
sets::marker::bind(const query_options& options) {
const auto& value = options.get_value_at(_bind_index);
if (value.is_null()) {
return nullptr;
} else if (value.is_unset_value()) {
return constants::UNSET_VALUE;
} else {
auto& type = dynamic_cast<const set_type_impl&>(_receiver->type->without_reversed());
try {
value.validate(type, options.get_cql_serialization_format());
} catch (marshal_exception& e) {
throw exceptions::invalid_request_exception(
format("Exception while binding column {:s}: {:s}", _receiver->name->to_cql_string(), e.what()));
}
return make_shared<cql3::sets::value>(value::from_serialized(value, type, options.get_cql_serialization_format()));
}
}

expr::expression sets::marker::to_expression() {
return expr::bind_variable {
.shape = expr::bind_variable::shape_type::scalar,
.bind_index = _bind_index,
.value_type = _receiver->type
};
}

void
sets::setter::execute(mutation& m, const clustering_key_prefix& row_key, const update_parameters& params) {
expr::constant value = expr::evaluate(_t, params._options);
expr::constant value = expr::evaluate(*_e, params._options);
execute(m, row_key, params, column, std::move(value));
}

Expand All @@ -196,7 +48,7 @@ sets::setter::execute(mutation& m, const clustering_key_prefix& row_key, const u

void
sets::adder::execute(mutation& m, const clustering_key_prefix& row_key, const update_parameters& params) {
const expr::constant value = expr::evaluate(_t, params._options);
const expr::constant value = expr::evaluate(*_e, params._options);
if (value.is_unset_value()) {
return;
}
Expand Down Expand Up @@ -229,7 +81,7 @@ sets::adder::do_add(mutation& m, const clustering_key_prefix& row_key, const upd
m.set_cell(row_key, column, mut.serialize(set_type));
} else if (!value.is_null()) {
// for frozen sets, we're overwriting the whole cell
m.set_cell(row_key, column, params.make_cell(*column.type, value.value.to_view()));
m.set_cell(row_key, column, params.make_cell(*column.type, value.view()));
} else {
m.set_cell(row_key, column, params.make_dead_cell());
}
Expand All @@ -239,7 +91,7 @@ void
sets::discarder::execute(mutation& m, const clustering_key_prefix& row_key, const update_parameters& params) {
assert(column.type->is_multi_cell()); // "Attempted to remove items from a frozen set";

expr::constant svalue = expr::evaluate(_t, params._options);
expr::constant svalue = expr::evaluate(*_e, params._options);
if (svalue.is_null_or_unset()) {
return;
}
Expand All @@ -257,7 +109,7 @@ sets::discarder::execute(mutation& m, const clustering_key_prefix& row_key, cons
void sets::element_discarder::execute(mutation& m, const clustering_key_prefix& row_key, const update_parameters& params)
{
assert(column.type->is_multi_cell() && "Attempted to remove items from a frozen set");
expr::constant elt = expr::evaluate(_t, params._options);
expr::constant elt = expr::evaluate(*_e, params._options);
if (elt.is_null()) {
throw exceptions::invalid_request_exception("Invalid null set element");
}
Expand Down
52 changes: 8 additions & 44 deletions cql3/sets.hh
Original file line number Diff line number Diff line change
Expand Up @@ -58,55 +58,19 @@ class sets {
public:
static lw_shared_ptr<column_specification> value_spec_of(const column_specification& column);

class value : public terminal, collection_terminal {
public:
std::set<managed_bytes, serialized_compare> _elements;
public:
value(std::set<managed_bytes, serialized_compare> elements, data_type my_type)
: terminal(std::move(my_type)), _elements(std::move(elements)) {
}
static value from_serialized(const raw_value_view& v, const set_type_impl& type, cql_serialization_format sf);
virtual cql3::raw_value get(const query_options& options) override;
virtual managed_bytes get_with_protocol_version(cql_serialization_format sf) override;
bool equals(const set_type_impl& st, const value& v);
virtual sstring to_string() const override;
};

// See Lists.DelayedValue
class delayed_value : public non_terminal {
std::vector<shared_ptr<term>> _elements;
data_type _my_type;
public:
delayed_value(std::vector<shared_ptr<term>> elements, data_type my_type)
: _elements(std::move(elements)), _my_type(std::move(my_type)) {
}
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;

virtual expr::expression to_expression() override;
};

class marker : public abstract_marker {
public:
marker(int32_t bind_index, lw_shared_ptr<column_specification> receiver);
virtual ::shared_ptr<terminal> bind(const query_options& options) override;
virtual expr::expression to_expression() override;
};

class setter : public operation {
public:
setter(const column_definition& column, shared_ptr<term> t)
: operation(column, std::move(t)) {
setter(const column_definition& column, expr::expression e)
: operation(column, std::move(e)) {
}
virtual void execute(mutation& m, const clustering_key_prefix& row_key, const update_parameters& params) override;
static void execute(mutation& m, const clustering_key_prefix& row_key, const update_parameters& params, const column_definition& column, const expr::constant& value);
};

class adder : public operation {
public:
adder(const column_definition& column, shared_ptr<term> t)
: operation(column, std::move(t)) {
adder(const column_definition& column, expr::expression e)
: operation(column, std::move(e)) {
}
virtual void execute(mutation& m, const clustering_key_prefix& row_key, const update_parameters& params) override;
static void do_add(mutation& m, const clustering_key_prefix& row_key, const update_parameters& params,
Expand All @@ -116,16 +80,16 @@ public:
// Note that this is reused for Map subtraction too (we subtract a set from a map)
class discarder : public operation {
public:
discarder(const column_definition& column, shared_ptr<term> t)
: operation(column, std::move(t)) {
discarder(const column_definition& column, expr::expression e)
: operation(column, std::move(e)) {
}
virtual void execute(mutation& m, const clustering_key_prefix& row_key, const update_parameters& params) override;
};

class element_discarder : public operation {
public:
element_discarder(const column_definition& column, shared_ptr<term> t)
: operation(column, std::move(t)) { }
element_discarder(const column_definition& column, expr::expression e)
: operation(column, std::move(e)) { }
virtual void execute(mutation& m, const clustering_key_prefix& row_key, const update_parameters& params) override;
};
};
Expand Down
47 changes: 26 additions & 21 deletions cql3/single_column_relation.cc
Original file line number Diff line number Diff line change
Expand Up @@ -54,17 +54,17 @@ using namespace cql3::expr;

namespace cql3 {

::shared_ptr<term>
single_column_relation::to_term(const std::vector<lw_shared_ptr<column_specification>>& receivers,
const expr::expression& raw,
database& db,
const sstring& keyspace,
prepare_context& ctx) const {
expression
single_column_relation::to_expression(const std::vector<lw_shared_ptr<column_specification>>& receivers,
const expr::expression& raw,
database& db,
const sstring& keyspace,
prepare_context& ctx) const {
// TODO: optimize vector away, accept single column_specification
assert(receivers.size() == 1);
auto term = prepare_term(raw, db, keyspace, receivers[0]);
term->fill_prepare_context(ctx);
return term;
auto expr = prepare_expression(raw, db, keyspace, receivers[0]);
expr::fill_prepare_context(expr, ctx);
return expr;
}

::shared_ptr<restrictions::restriction>
Expand All @@ -76,13 +76,13 @@ single_column_relation::new_EQ_restriction(database& db, schema_ptr schema, prep
}
if (!_map_key) {
auto r = ::make_shared<restrictions::single_column_restriction>(column_def);
auto term = to_term(to_receivers(*schema, column_def), *_value, db, schema->ks_name(), ctx);
r->expression = binary_operator{column_value{&column_def}, expr::oper_t::EQ, std::move(term)};
auto e = to_expression(to_receivers(*schema, column_def), *_value, db, schema->ks_name(), ctx);
r->expression = binary_operator{column_value{&column_def}, expr::oper_t::EQ, std::move(e)};
return r;
}
auto&& receivers = to_receivers(*schema, column_def);
auto&& entry_key = to_term({receivers[0]}, *_map_key, db, schema->ks_name(), ctx);
auto&& entry_value = to_term({receivers[1]}, *_value, db, schema->ks_name(), ctx);
auto&& entry_key = to_expression({receivers[0]}, *_map_key, db, schema->ks_name(), ctx);
auto&& entry_value = to_expression({receivers[1]}, *_value, db, schema->ks_name(), ctx);
auto r = make_shared<restrictions::single_column_restriction>(column_def);
r->expression = binary_operator{
column_value(&column_def, std::move(entry_key)), oper_t::EQ, std::move(entry_value)};
Expand All @@ -100,23 +100,28 @@ single_column_relation::new_IN_restriction(database& db, schema_ptr schema, prep
auto receivers = to_receivers(*schema, column_def);
assert(_in_values.empty() || !_value);
if (_value) {
auto term = to_term(receivers, *_value, db, schema->ks_name(), ctx);
auto e = to_expression(receivers, *_value, db, schema->ks_name(), ctx);
auto r = ::make_shared<single_column_restriction>(column_def);
r->expression = binary_operator{column_value{&column_def}, expr::oper_t::IN, std::move(term)};
r->expression = binary_operator{column_value{&column_def}, expr::oper_t::IN, std::move(e)};
return r;
}
auto terms = to_terms(receivers, _in_values, db, schema->ks_name(), ctx);
auto expressions = to_expressions(receivers, _in_values, db, schema->ks_name(), ctx);
// Convert a single-item IN restriction to an EQ restriction
if (terms.size() == 1) {
if (expressions.size() == 1) {
auto r = ::make_shared<single_column_restriction>(column_def);
r->expression = binary_operator{column_value{&column_def}, expr::oper_t::EQ, std::move(terms[0])};
r->expression = binary_operator{column_value{&column_def}, expr::oper_t::EQ, std::move(expressions[0])};
return r;
}
auto r = ::make_shared<single_column_restriction>(column_def);
collection_constructor list_value {
.style = collection_constructor::style_type::list,
.elements = std::move(expressions),
.type = list_type_impl::get_instance(column_def.type, false),
};
r->expression = binary_operator{
column_value{&column_def},
expr::oper_t::IN,
::make_shared<lists::delayed_value>(std::move(terms), list_type_impl::get_instance(column_def.type, false))};
std::move(list_value)};
return r;
}

Expand All @@ -128,9 +133,9 @@ single_column_relation::new_LIKE_restriction(
throw exceptions::invalid_request_exception(
format("LIKE is allowed only on string types, which {} is not", column_def.name_as_text()));
}
auto term = to_term(to_receivers(*schema, column_def), *_value, db, schema->ks_name(), ctx);
auto e = to_expression(to_receivers(*schema, column_def), *_value, db, schema->ks_name(), ctx);
auto r = ::make_shared<restrictions::single_column_restriction>(column_def);
r->expression = binary_operator{column_value{&column_def}, expr::oper_t::LIKE, std::move(term)};
r->expression = binary_operator{column_value{&column_def}, expr::oper_t::LIKE, std::move(e)};
return r;
}

Expand Down
15 changes: 7 additions & 8 deletions cql3/single_column_relation.hh
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@
#include "cql3/relation.hh"
#include "cql3/column_identifier.hh"
#include "cql3/expr/expression.hh"
#include "cql3/term.hh"
#include "types/collection.hh"

namespace cql3 {
Expand Down Expand Up @@ -115,9 +114,9 @@ public:
}

protected:
virtual ::shared_ptr<term> to_term(const std::vector<lw_shared_ptr<column_specification>>& receivers,
const expr::expression& raw, database& db, const sstring& keyspace,
prepare_context& ctx) const override;
virtual expr::expression to_expression(const std::vector<lw_shared_ptr<column_specification>>& receivers,
const expr::expression& raw, database& db, const sstring& keyspace,
prepare_context& ctx) const override;

#if 0
public SingleColumnRelation withNonStrictOperator()
Expand Down Expand Up @@ -169,20 +168,20 @@ protected:
throw exceptions::invalid_request_exception("Slice restrictions are not supported on duration columns");
}

auto term = to_term(to_receivers(*schema, column_def), *_value, db, schema->ks_name(), ctx);
auto e = to_expression(to_receivers(*schema, column_def), *_value, db, schema->ks_name(), ctx);
auto r = ::make_shared<restrictions::single_column_restriction>(column_def);
r->expression = expr::binary_operator{expr::column_value{&column_def}, _relation_type, std::move(term)};
r->expression = expr::binary_operator{expr::column_value{&column_def}, _relation_type, std::move(e)};
return r;
}

virtual shared_ptr<restrictions::restriction> new_contains_restriction(database& db, schema_ptr schema,
prepare_context& ctx,
bool is_key) override {
auto&& column_def = to_column_definition(*schema, *_entity);
auto term = to_term(to_receivers(*schema, column_def), *_value, db, schema->ks_name(), ctx);
auto e = to_expression(to_receivers(*schema, column_def), *_value, db, schema->ks_name(), ctx);
auto r = ::make_shared<restrictions::single_column_restriction>(column_def);
r->expression = expr::binary_operator{
expr::column_value{&column_def}, is_key ? expr::oper_t::CONTAINS_KEY : expr::oper_t::CONTAINS, std::move(term)};
expr::column_value{&column_def}, is_key ? expr::oper_t::CONTAINS_KEY : expr::oper_t::CONTAINS, std::move(e)};
return r;
}

Expand Down
1 change: 1 addition & 0 deletions cql3/statements/batch_statement.hh
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
#include "raw/batch_statement.hh"
#include "timestamp.hh"
#include "log.hh"
#include "service_permit.hh"

namespace cql_transport::messages {
class result_message;
Expand Down
4 changes: 2 additions & 2 deletions cql3/statements/create_aggregate_statement.cc
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,8 @@ void create_aggregate_statement::create(service::storage_proxy& proxy, functions

auto dummy_ident = ::make_shared<column_identifier>("", true);
auto column_spec = make_lw_shared<column_specification>("", "", dummy_ident, state_type);
auto initcond_term = prepare_term(_ival, db, _name.keyspace, {column_spec});
bytes_opt initcond = to_bytes(*to_managed_bytes_opt(expr::evaluate_to_raw_view(initcond_term, cql3::query_options::DEFAULT)));
auto initcond_term = expr::evaluate(prepare_expression(_ival, db, _name.keyspace, {column_spec}), query_options::DEFAULT);
bytes_opt initcond = std::move(initcond_term.value).to_bytes();

_aggregate = ::make_shared<functions::user_aggregate>(_name, initcond, std::move(state_func), std::move(final_func));
return;
Expand Down
1 change: 0 additions & 1 deletion cql3/statements/delete_statement.cc
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@
#include <boost/algorithm/cxx11/all_of.hpp>
#include <boost/range/adaptors.hpp>

#include "cql3/tuples.hh"
#include "database.hh"
#include "delete_statement.hh"
#include "raw/delete_statement.hh"
Expand Down
6 changes: 2 additions & 4 deletions cql3/statements/modification_statement.cc
Original file line number Diff line number Diff line change
Expand Up @@ -499,10 +499,8 @@ modification_statement::prepare(database& db, prepare_context& ctx, cql_stats& s
// Since this cache is only meaningful for LWT queries, just clear the ids
// if it's not a conditional statement so that the AST nodes don't
// participate in the caching mechanism later.
if (!prepared_stmt->has_conditions()) {
for (auto& fn : ctx.pk_function_calls()) {
fn->set_id(std::nullopt);
}
if (!prepared_stmt->has_conditions() && prepared_stmt->_restrictions.has_value()) {
ctx.clear_pk_function_calls_cache();
}
return prepared_stmt;
}
Expand Down
2 changes: 0 additions & 2 deletions cql3/statements/raw/insert_statement.hh
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,7 @@

#include "cql3/statements/raw/modification_statement.hh"
#include "cql3/column_identifier.hh"
#include "cql3/term.hh"
#include "cql3/expr/expression.hh"

#include "database_fwd.hh"

#include <vector>
Expand Down
4 changes: 2 additions & 2 deletions cql3/statements/raw/select_statement.hh
Original file line number Diff line number Diff line change
Expand Up @@ -133,8 +133,8 @@ private:
bool for_view = false,
bool allow_filtering = false);

/** Returns a ::shared_ptr<term> for the limit or null if no limit is set */
::shared_ptr<term> prepare_limit(database& db, prepare_context& ctx, const std::optional<expr::expression>& limit);
/** Returns an expression for the limit or nullopt if no limit is set */
std::optional<expr::expression> prepare_limit(database& db, prepare_context& ctx, const std::optional<expr::expression>& limit);

static void verify_ordering_is_allowed(const restrictions::statement_restrictions& restrictions);

Expand Down
2 changes: 1 addition & 1 deletion cql3/statements/raw/update_statement.hh
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ private:
public:
/**
* Creates a new UpdateStatement from a column family name, columns map, consistency
* level, and key term.
* level, and key expression.
*
* @param name column family being operated on
* @param attrs additional attributes for statement (timestamp, timeToLive)
Expand Down
44 changes: 23 additions & 21 deletions cql3/statements/select_statement.cc
Original file line number Diff line number Diff line change
Expand Up @@ -140,8 +140,8 @@ select_statement::select_statement(schema_ptr schema,
::shared_ptr<std::vector<size_t>> group_by_cell_indices,
bool is_reversed,
ordering_comparator_type ordering_comparator,
::shared_ptr<term> limit,
::shared_ptr<term> per_partition_limit,
std::optional<expr::expression> limit,
std::optional<expr::expression> per_partition_limit,
cql_stats& stats,
std::unique_ptr<attributes> attrs)
: cql_statement(select_timeout(*restrictions))
Expand Down Expand Up @@ -251,20 +251,22 @@ select_statement::make_partition_slice(const query_options& options) const
std::move(static_columns), std::move(regular_columns), _opts, nullptr, options.get_cql_serialization_format(), get_per_partition_limit(options));
}

uint64_t select_statement::do_get_limit(const query_options& options, ::shared_ptr<term> limit, uint64_t default_limit) const {
if (!limit || _selection->is_aggregate()) {
uint64_t select_statement::do_get_limit(const query_options& options,
const std::optional<expr::expression>& limit,
uint64_t default_limit) const {
if (!limit.has_value() || _selection->is_aggregate()) {
return default_limit;
}

auto val = expr::evaluate_to_raw_view(limit, options);
auto val = expr::evaluate(*limit, options);
if (val.is_null()) {
throw exceptions::invalid_request_exception("Invalid null value of limit");
}
if (val.is_unset_value()) {
return default_limit;
}
try {
auto l = val.validate_and_deserialize<int32_t>(*int32_type, options.get_cql_serialization_format());
auto l = val.view().validate_and_deserialize<int32_t>(*int32_type, cql_serialization_format::internal());
if (l <= 0) {
throw exceptions::invalid_request_exception("LIMIT must be strictly positive");
}
Expand Down Expand Up @@ -820,11 +822,11 @@ primary_key_select_statement::primary_key_select_statement(schema_ptr schema, ui
::shared_ptr<std::vector<size_t>> group_by_cell_indices,
bool is_reversed,
ordering_comparator_type ordering_comparator,
::shared_ptr<term> limit,
::shared_ptr<term> per_partition_limit,
std::optional<expr::expression> limit,
std::optional<expr::expression> per_partition_limit,
cql_stats &stats,
std::unique_ptr<attributes> attrs)
: select_statement{schema, bound_terms, parameters, selection, restrictions, group_by_cell_indices, is_reversed, ordering_comparator, limit, per_partition_limit, stats, std::move(attrs)}
: select_statement{schema, bound_terms, parameters, selection, restrictions, group_by_cell_indices, is_reversed, ordering_comparator, std::move(limit), std::move(per_partition_limit), stats, std::move(attrs)}
{
if (_ks_sel == ks_selector::NONSYSTEM) {
if (_restrictions->need_filtering() ||
Expand All @@ -848,8 +850,8 @@ indexed_table_select_statement::prepare(database& db,
::shared_ptr<std::vector<size_t>> group_by_cell_indices,
bool is_reversed,
ordering_comparator_type ordering_comparator,
::shared_ptr<term> limit,
::shared_ptr<term> per_partition_limit,
std::optional<expr::expression> limit,
std::optional<expr::expression> per_partition_limit,
cql_stats &stats,
std::unique_ptr<attributes> attrs)
{
Expand Down Expand Up @@ -878,8 +880,8 @@ indexed_table_select_statement::prepare(database& db,
std::move(group_by_cell_indices),
is_reversed,
std::move(ordering_comparator),
limit,
per_partition_limit,
std::move(limit),
std::move(per_partition_limit),
stats,
*index_opt,
std::move(used_index_restrictions),
Expand All @@ -895,8 +897,8 @@ indexed_table_select_statement::indexed_table_select_statement(schema_ptr schema
::shared_ptr<std::vector<size_t>> group_by_cell_indices,
bool is_reversed,
ordering_comparator_type ordering_comparator,
::shared_ptr<term> limit,
::shared_ptr<term> per_partition_limit,
std::optional<expr::expression> limit,
std::optional<expr::expression> per_partition_limit,
cql_stats &stats,
const secondary_index::index& index,
::shared_ptr<restrictions::restrictions> used_index_restrictions,
Expand Down Expand Up @@ -1477,16 +1479,16 @@ select_statement::prepare_restrictions(database& db,
}
}

/** Returns a ::shared_ptr<term> for the limit or null if no limit is set */
::shared_ptr<term>
/** Returns a expr::expression for the limit or nullopt if no limit is set */
std::optional<expr::expression>
select_statement::prepare_limit(database& db, prepare_context& ctx, const std::optional<expr::expression>& limit)
{
if (!limit) {
return {};
if (!limit.has_value()) {
return std::nullopt;
}

auto prep_limit = prepare_term(*limit, db, keyspace(), limit_receiver());
prep_limit->fill_prepare_context(ctx);
expr::expression prep_limit = prepare_expression(*limit, db, keyspace(), limit_receiver());
expr::fill_prepare_context(prep_limit, ctx);
return prep_limit;
}

Expand Down
22 changes: 11 additions & 11 deletions cql3/statements/select_statement.hh
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,8 @@ protected:
::shared_ptr<restrictions::statement_restrictions> _restrictions;
::shared_ptr<std::vector<size_t>> _group_by_cell_indices; ///< Indices in result row of cells holding GROUP BY values.
bool _is_reversed;
::shared_ptr<term> _limit;
::shared_ptr<term> _per_partition_limit;
std::optional<expr::expression> _limit;
std::optional<expr::expression> _per_partition_limit;

template<typename T>
using compare_fn = raw::select_statement::compare_fn<T>;
Expand Down Expand Up @@ -118,8 +118,8 @@ public:
::shared_ptr<std::vector<size_t>> group_by_cell_indices,
bool is_reversed,
ordering_comparator_type ordering_comparator,
::shared_ptr<term> limit,
::shared_ptr<term> per_partition_limit,
std::optional<expr::expression> limit,
std::optional<expr::expression> per_partition_limit,
cql_stats& stats,
std::unique_ptr<cql3::attributes> attrs);

Expand Down Expand Up @@ -158,7 +158,7 @@ public:
db::timeout_clock::duration get_timeout(const service::client_state& state, const query_options& options) const;

protected:
uint64_t do_get_limit(const query_options& options, ::shared_ptr<term> limit, uint64_t default_limit) const;
uint64_t do_get_limit(const query_options& options, const std::optional<expr::expression>& limit, uint64_t default_limit) const;
uint64_t get_limit(const query_options& options) const {
return do_get_limit(options, _limit, query::max_rows);
}
Expand All @@ -181,8 +181,8 @@ public:
::shared_ptr<std::vector<size_t>> group_by_cell_indices,
bool is_reversed,
ordering_comparator_type ordering_comparator,
::shared_ptr<term> limit,
::shared_ptr<term> per_partition_limit,
std::optional<expr::expression> limit,
std::optional<expr::expression> per_partition_limit,
cql_stats &stats,
std::unique_ptr<cql3::attributes> attrs);
};
Expand All @@ -205,8 +205,8 @@ public:
::shared_ptr<std::vector<size_t>> group_by_cell_indices,
bool is_reversed,
ordering_comparator_type ordering_comparator,
::shared_ptr<term> limit,
::shared_ptr<term> per_partition_limit,
std::optional<expr::expression> limit,
std::optional<expr::expression> per_partition_limit,
cql_stats &stats,
std::unique_ptr<cql3::attributes> attrs);

Expand All @@ -218,8 +218,8 @@ public:
::shared_ptr<std::vector<size_t>> group_by_cell_indices,
bool is_reversed,
ordering_comparator_type ordering_comparator,
::shared_ptr<term> limit,
::shared_ptr<term> per_partition_limit,
std::optional<expr::expression> limit,
std::optional<expr::expression> per_partition_limit,
cql_stats &stats,
const secondary_index::index& index,
::shared_ptr<restrictions::restrictions> used_index_restrictions,
Expand Down
28 changes: 13 additions & 15 deletions cql3/statements/update_statement.cc
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ void update_statement::add_update_for_key(mutation& m, const query::clustering_r
if (rb->name().empty() || rb->type == empty_type) {
// There is no column outside the PK. So no operation could have passed through validation
assert(_column_operations.empty());
constants::setter(*s->regular_begin(), make_shared<constants::value>(cql3::raw_value::make_value(bytes()), empty_type)).execute(m, prefix, params);
constants::setter(*s->regular_begin(), expr::constant(cql3::raw_value::make_value(bytes()), empty_type)).execute(m, prefix, params);
} else {
// dense means we don't have a row marker, so don't accept to set only the PK. See CASSANDRA-5648.
if (_column_operations.empty()) {
Expand Down Expand Up @@ -180,8 +180,9 @@ void update_statement::add_update_for_key(mutation& m, const query::clustering_r
}

modification_statement::json_cache_opt insert_prepared_json_statement::maybe_prepare_json_cache(const query_options& options) const {
sstring json_string = utf8_type->to_string(to_bytes(expr::evaluate_to_raw_view(_term, options)));
return json_helpers::parse(std::move(json_string), s->all_columns(), options.get_cql_serialization_format());
expr::constant c = expr::evaluate(_value, options);
sstring json_string = utf8_type->to_string(to_bytes(c.view()));
return json_helpers::parse(std::move(json_string), s->all_columns(), cql_serialization_format::internal());
}

void
Expand Down Expand Up @@ -212,29 +213,26 @@ insert_prepared_json_statement::execute_set_value(mutation& m, const clustering_
return;
}

cql_serialization_format sf = params._options.get_cql_serialization_format();

expr::constant val(raw_value::make_value(*value), column.type);
visit(*column.type, make_visitor(
[&] (const list_type_impl& ltype) {
auto val = ::make_shared<lists::value>(lists::value::from_serialized(raw_value_view::make_value(*value), ltype, sf));
lists::setter::execute(m, prefix, params, column, expr::evaluate(val, query_options::DEFAULT));
lists::setter::execute(m, prefix, params, column, val);
},
[&] (const set_type_impl& stype) {
auto val = ::make_shared<sets::value>(sets::value::from_serialized(raw_value_view::make_value(*value), stype, sf));
sets::setter::execute(m, prefix, params, column, expr::evaluate(val, query_options::DEFAULT));
sets::setter::execute(m, prefix, params, column, val);
},
[&] (const map_type_impl& mtype) {
auto val = ::make_shared<maps::value>(maps::value::from_serialized(raw_value_view::make_value(*value), mtype, sf));
maps::setter::execute(m, prefix, params, column, expr::evaluate(val, query_options::DEFAULT));
maps::setter::execute(m, prefix, params, column, val);
},
[&] (const user_type_impl& utype) {
auto val = ::make_shared<user_types::value>(user_types::value::from_serialized(raw_value_view::make_value(*value), utype));
user_types::setter::execute(m, prefix, params, column, expr::evaluate(val, query_options::DEFAULT));
user_types::setter::execute(m, prefix, params, column, val);
},
[&] (const abstract_type& type) {
if (type.is_collection()) {
throw std::runtime_error(format("insert_prepared_json_statement::execute_set_value: unhandled collection type {}", type.name()));
}
constants::setter::execute(m, prefix, params, column, raw_value_view::make_value(*value));
constants::setter::execute(m, prefix, params, column, val.view());
}
));
}
Expand Down Expand Up @@ -365,8 +363,8 @@ insert_json_statement::prepare_internal(database& db, schema_ptr schema,
(void)_if_not_exists;
assert(expr::is<cql3::expr::untyped_constant>(_json_value) || expr::is<cql3::expr::bind_variable>(_json_value));
auto json_column_placeholder = ::make_shared<column_identifier>("", true);
auto prepared_json_value = prepare_term(_json_value, db, "", make_lw_shared<column_specification>("", "", json_column_placeholder, utf8_type));
prepared_json_value->fill_prepare_context(ctx);
auto prepared_json_value = prepare_expression(_json_value, db, "", make_lw_shared<column_specification>("", "", json_column_placeholder, utf8_type));
expr::fill_prepare_context(prepared_json_value, ctx);
auto stmt = ::make_shared<cql3::statements::insert_prepared_json_statement>(ctx.bound_variables_size(), schema, std::move(attrs), stats, std::move(prepared_json_value), _default_unset);
prepare_conditions(db, *schema, ctx, *stmt);
return stmt;
Expand Down
8 changes: 3 additions & 5 deletions cql3/statements/update_statement.hh
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,6 @@

namespace cql3 {

class term;

namespace statements {

/**
Expand Down Expand Up @@ -82,17 +80,17 @@ private:
* Overridden add_update_for_key uses this parsed JSON to look up values for columns.
*/
class insert_prepared_json_statement : public update_statement {
::shared_ptr<term> _term;
expr::expression _value;
bool _default_unset;
public:
insert_prepared_json_statement(
uint32_t bound_terms,
schema_ptr s,
std::unique_ptr<attributes> attrs,
cql_stats& stats,
::shared_ptr<term> t, bool default_unset)
expr::expression v, bool default_unset)
: update_statement(statement_type::INSERT, bound_terms, s, std::move(attrs), stats)
, _term(t)
, _value(std::move(v))
, _default_unset(default_unset) {
_restrictions = restrictions::statement_restrictions(s, false);
}
Expand Down
179 changes: 0 additions & 179 deletions cql3/term.hh

This file was deleted.

17 changes: 8 additions & 9 deletions cql3/token_relation.cc
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@
#include "restrictions/token_restriction.hh"
#include "token_relation.hh"
#include "column_identifier.hh"
#include "term.hh"
#include "to_string.hh"

std::vector<const column_definition*> cql3::token_relation::get_column_definitions(const schema& s) {
Expand Down Expand Up @@ -83,11 +82,11 @@ ::shared_ptr<cql3::restrictions::restriction> cql3::token_relation::new_EQ_restr
database& db, schema_ptr schema,
prepare_context& ctx) {
auto column_defs = get_column_definitions(*schema);
auto term = to_term(to_receivers(*schema, column_defs), _value, db,
auto e = to_expression(to_receivers(*schema, column_defs), _value, db,
schema->ks_name(), ctx);
auto r = ::make_shared<restrictions::token_restriction>(column_defs);
using namespace expr;
r->expression = binary_operator{token{}, oper_t::EQ, std::move(term)};
r->expression = binary_operator{token{}, oper_t::EQ, std::move(e)};
return r;
}

Expand All @@ -105,11 +104,11 @@ ::shared_ptr<cql3::restrictions::restriction> cql3::token_relation::new_slice_re
statements::bound bound,
bool inclusive) {
auto column_defs = get_column_definitions(*schema);
auto term = to_term(to_receivers(*schema, column_defs), _value, db,
auto e = to_expression(to_receivers(*schema, column_defs), _value, db,
schema->ks_name(), ctx);
auto r = ::make_shared<restrictions::token_restriction>(column_defs);
using namespace expr;
r->expression = binary_operator{token{}, pick_operator(bound, inclusive), std::move(term)};
r->expression = binary_operator{token{}, pick_operator(bound, inclusive), std::move(e)};
return r;
}

Expand All @@ -130,13 +129,13 @@ sstring cql3::token_relation::to_string() const {
return format("token({}) {} {}", join(", ", _entities), get_operator(), _value);
}

::shared_ptr<cql3::term> cql3::token_relation::to_term(
cql3::expr::expression cql3::token_relation::to_expression(
const std::vector<lw_shared_ptr<column_specification>>& receivers,
const expr::expression& raw, database& db, const sstring& keyspace,
prepare_context& ctx) const {
auto term = expr::prepare_term(raw, db, keyspace, receivers.front());
term->fill_prepare_context(ctx);
return term;
auto e = expr::prepare_expression(raw, db, keyspace, receivers.front());
expr::fill_prepare_context(e, ctx);
return e;
}

::shared_ptr<cql3::relation> cql3::token_relation::maybe_rename_identifier(const cql3::column_identifier::raw& from, cql3::column_identifier::raw to) {
Expand Down
11 changes: 5 additions & 6 deletions cql3/token_relation.hh
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@

#include "relation.hh"
#include "column_identifier.hh"
#include "term.hh"
#include "restrictions/restriction.hh"
#include "expr/expression.hh"

Expand Down Expand Up @@ -123,11 +122,11 @@ public:
sstring to_string() const override;

protected:
::shared_ptr<term> to_term(const std::vector<lw_shared_ptr<column_specification>>& receivers,
const expr::expression& raw,
database& db,
const sstring& keyspace,
prepare_context& ctx) const override;
expr::expression to_expression(const std::vector<lw_shared_ptr<column_specification>>& receivers,
const expr::expression& raw,
database& db,
const sstring& keyspace,
prepare_context& ctx) const override;
};

}
126 changes: 0 additions & 126 deletions cql3/tuples.cc

This file was deleted.

211 changes: 0 additions & 211 deletions cql3/tuples.hh

This file was deleted.

16 changes: 7 additions & 9 deletions cql3/type_json.cc
Original file line number Diff line number Diff line change
Expand Up @@ -101,31 +101,29 @@ static bytes from_json_object_aux(const map_type_impl& t, const rjson::value& va
if (!value.IsObject()) {
throw marshal_exception("map_type must be represented as JSON Object");
}
std::vector<bytes> raw_map;
raw_map.reserve(value.MemberCount());
std::map<bytes, bytes, serialized_compare> raw_map(t.get_keys_type()->as_less_comparator());
for (auto it = value.MemberBegin(); it != value.MemberEnd(); ++it) {
bytes value = from_json_object(*t.get_values_type(), it->value, sf);
if (!t.get_keys_type()->is_compatible_with(*utf8_type)) {
// Keys in maps can only be strings in JSON, but they can also be a string representation
// of another JSON type, which needs to be reparsed. Example - map<frozen<list<int>>, int>
// will be represented like this: { "[1, 3, 6]": 3, "[]": 0, "[1, 2]": 2 }
rjson::value map_key = rjson::parse(rjson::to_string_view(it->name));
raw_map.emplace_back(from_json_object(*t.get_keys_type(), map_key, sf));
raw_map.emplace(from_json_object(*t.get_keys_type(), map_key, sf), std::move(value));
} else {
raw_map.emplace_back(from_json_object(*t.get_keys_type(), it->name, sf));
raw_map.emplace(from_json_object(*t.get_keys_type(), it->name, sf), std::move(value));
}
raw_map.emplace_back(from_json_object(*t.get_values_type(), it->value, sf));
}
return collection_type_impl::pack(raw_map.begin(), raw_map.end(), raw_map.size() / 2, sf);
return map_type_impl::serialize_to_bytes(raw_map);
}

static bytes from_json_object_aux(const set_type_impl& t, const rjson::value& value, cql_serialization_format sf) {
if (!value.IsArray()) {
throw marshal_exception("set_type must be represented as JSON Array");
}
std::vector<bytes> raw_set;
raw_set.reserve(value.Size());
std::set<bytes, serialized_compare> raw_set(t.get_elements_type()->as_less_comparator());
for (const rjson::value& v : value.GetArray()) {
raw_set.emplace_back(from_json_object(*t.get_elements_type(), v, sf));
raw_set.emplace(from_json_object(*t.get_elements_type(), v, sf));
}
return collection_type_impl::pack(raw_set.begin(), raw_set.end(), raw_set.size(), sf);
}
Expand Down
112 changes: 5 additions & 107 deletions cql3/user_types.cc
Original file line number Diff line number Diff line change
Expand Up @@ -49,110 +49,8 @@
#include "types/user.hh"

namespace cql3 {

user_types::value::value(std::vector<managed_bytes_opt> elements, data_type my_type)
: terminal(std::move(my_type)), _elements(std::move(elements)) {
}

user_types::value user_types::value::from_serialized(const raw_value_view& v, const user_type_impl& type) {
return v.with_value([&] (const FragmentedView auto& val) {
std::vector<managed_bytes_opt> elements = type.split_fragmented(val);
if (elements.size() > type.size()) {
throw exceptions::invalid_request_exception(
format("User Defined Type value contained too many fields (expected {}, got {})", type.size(), elements.size()));
}

return value(std::move(elements), type.shared_from_this());
});
}

cql3::raw_value user_types::value::get(const query_options&) {
return cql3::raw_value::make_value(tuple_type_impl::build_value_fragmented(_elements));
}

sstring user_types::value::to_string() const {
return format("({})", join(", ", _elements));
}

user_types::delayed_value::delayed_value(user_type type, std::vector<shared_ptr<term>> values)
: _type(std::move(type)), _values(std::move(values)) {
}
bool user_types::delayed_value::contains_bind_marker() const {
return boost::algorithm::any_of(_values, std::mem_fn(&term::contains_bind_marker));
}

void user_types::delayed_value::fill_prepare_context(prepare_context& ctx) const {
for (auto&& v : _values) {
v->fill_prepare_context(ctx);
}
}

std::vector<managed_bytes_opt> user_types::delayed_value::bind_internal(const query_options& options) {
auto sf = options.get_cql_serialization_format();

// user_types::literal::prepare makes sure that every field gets a corresponding value.
// For missing fields the values become nullopts.
assert(_type->size() == _values.size());

std::vector<managed_bytes_opt> buffers;
for (size_t i = 0; i < _type->size(); ++i) {
const auto& value = expr::evaluate_to_raw_view(_values[i], options);
if (!_type->is_multi_cell() && value.is_unset_value()) {
throw exceptions::invalid_request_exception(format("Invalid unset value for field '{}' of user defined type {}",
_type->field_name_as_string(i), _type->get_name_as_string()));
}

buffers.push_back(to_managed_bytes_opt(value));

// Inside UDT values, we must force the serialization of collections to v3 whatever protocol
// version is in use since we're going to store directly that serialized value.
if (!sf.collection_format_unchanged() && _type->field_type(i)->is_collection() && buffers.back()) {
auto&& ctype = static_pointer_cast<const collection_type_impl>(_type->field_type(i));
buffers.back() = ctype->reserialize(sf, cql_serialization_format::latest(), managed_bytes_view(*buffers.back()));
}
}
return buffers;
}

shared_ptr<terminal> user_types::delayed_value::bind(const query_options& options) {
return ::make_shared<user_types::value>(bind_internal(options), _type);
}

expr::expression user_types::delayed_value::to_expression() {
expr::usertype_constructor::elements_map_type new_elements;
for (size_t i = 0; i < _values.size(); i++) {
column_identifier field_name(_type->field_names().at(i), _type->string_field_names().at(i));
expr::expression field_value(expr::to_expression(_values[i]));
new_elements.emplace(std::move(field_name), std::move(field_value));
}

return expr::usertype_constructor {
.elements = std::move(new_elements),
.type = _type
};
}

shared_ptr<terminal> user_types::marker::bind(const query_options& options) {
auto value = options.get_value_at(_bind_index);
if (value.is_null()) {
return nullptr;
}
if (value.is_unset_value()) {
return constants::UNSET_VALUE;
}
return make_shared<user_types::value>(value::from_serialized(value, static_cast<const user_type_impl&>(*_receiver->type)));
}

expr::expression user_types::marker::to_expression() {
return expr::bind_variable {
.shape = expr::bind_variable::shape_type::scalar,
.bind_index = _bind_index,
.value_type = _receiver->type
};
}

void user_types::setter::execute(mutation& m, const clustering_key_prefix& row_key, const update_parameters& params) {
const expr::constant value = expr::evaluate(_t, params._options);
const expr::constant value = expr::evaluate(*_e, params._options);
execute(m, row_key, params, column, value);
}

Expand Down Expand Up @@ -200,7 +98,7 @@ void user_types::setter::execute(mutation& m, const clustering_key_prefix& row_k
m.set_cell(row_key, column, mut.serialize(type));
} else {
if (!ut_value.is_null()) {
m.set_cell(row_key, column, params.make_cell(type, ut_value.value.to_view()));
m.set_cell(row_key, column, params.make_cell(type, ut_value.view()));
} else {
m.set_cell(row_key, column, params.make_dead_cell());
}
Expand All @@ -210,16 +108,16 @@ void user_types::setter::execute(mutation& m, const clustering_key_prefix& row_k
void user_types::setter_by_field::execute(mutation& m, const clustering_key_prefix& row_key, const update_parameters& params) {
assert(column.type->is_user_type() && column.type->is_multi_cell());

auto value = expr::evaluate_to_raw_view(_t, params._options);
auto value = expr::evaluate(*_e, params._options);
if (value.is_unset_value()) {
return;
}

auto& type = static_cast<const user_type_impl&>(*column.type);

collection_mutation_description mut;
mut.cells.emplace_back(serialize_field_index(_field_idx), value
? params.make_cell(*type.type(_field_idx), value, atomic_cell::collection_member::yes)
mut.cells.emplace_back(serialize_field_index(_field_idx), !value.is_null()
? params.make_cell(*type.type(_field_idx), value.view(), atomic_cell::collection_member::yes)
: params.make_dead_cell());

m.set_cell(row_key, column, mut.serialize(type));
Expand Down
46 changes: 3 additions & 43 deletions cql3/user_types.hh
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@

#include "cql3/abstract_marker.hh"
#include "column_specification.hh"
#include "term.hh"
#include "column_identifier.hh"
#include "operation.hh"
#include "to_string.hh"
Expand All @@ -57,45 +56,6 @@ class user_types {
public:
static lw_shared_ptr<column_specification> field_spec_of(const column_specification& column, size_t field);

class value : public terminal {
std::vector<managed_bytes_opt> _elements;
public:
explicit value(std::vector<managed_bytes_opt>, data_type my_type);

static value from_serialized(const raw_value_view&, const user_type_impl&);

virtual cql3::raw_value get(const query_options&) override;
virtual sstring to_string() const override;
};

// Same purpose than Lists.DelayedValue, except we do handle bind marker in that case
class delayed_value : public non_terminal {
user_type _type;
std::vector<shared_ptr<term>> _values;
public:
delayed_value(user_type type, std::vector<shared_ptr<term>> values);
virtual bool contains_bind_marker() const override;
virtual void fill_prepare_context(prepare_context& ctx) const override;
private:
std::vector<managed_bytes_opt> bind_internal(const query_options& options);
public:
virtual shared_ptr<terminal> bind(const query_options& options) override;

virtual expr::expression to_expression() override;
};

class marker : public abstract_marker {
public:
marker(int32_t bind_index, lw_shared_ptr<column_specification> receiver)
: abstract_marker{bind_index, std::move(receiver)}
{
assert(_receiver->type->is_user_type());
}

virtual shared_ptr<terminal> bind(const query_options& options) override;
virtual expr::expression to_expression() override;
};

class setter : public operation {
public:
using operation::operation;
Expand All @@ -107,8 +67,8 @@ public:
class setter_by_field : public operation {
size_t _field_idx;
public:
setter_by_field(const column_definition& column, size_t field_idx, shared_ptr<term> t)
: operation(column, std::move(t)), _field_idx(field_idx) {
setter_by_field(const column_definition& column, size_t field_idx, expr::expression e)
: operation(column, std::move(e)), _field_idx(field_idx) {
}

virtual void execute(mutation& m, const clustering_key_prefix& row_key, const update_parameters& params) override;
Expand All @@ -118,7 +78,7 @@ public:
size_t _field_idx;
public:
deleter_by_field(const column_definition& column, size_t field_idx)
: operation(column, nullptr), _field_idx(field_idx) {
: operation(column, std::nullopt), _field_idx(field_idx) {
}

virtual void execute(mutation& m, const clustering_key_prefix& row_key, const update_parameters& params) override;
Expand Down
9 changes: 4 additions & 5 deletions test/boost/statement_restrictions_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -420,8 +420,7 @@ BOOST_AUTO_TEST_CASE(expression_extract_column_restrictions) {
// AND pk1 AND pk2
// AND (pk1, pk2)
std::vector<expression> big_where;
::shared_ptr<constants::value> zero_value =
::make_shared<constants::value>(raw_value::make_value(I(0)), int32_type);
expr::constant zero_value = constant(raw_value::make_value(I(0)), int32_type);

expression pk1_restriction(binary_operator(column_value(&col_pk1), oper_t::EQ, zero_value));
expression pk2_restriction(binary_operator(column_value(&col_pk2), oper_t::EQ, zero_value));
Expand All @@ -438,10 +437,10 @@ BOOST_AUTO_TEST_CASE(expression_extract_column_restrictions) {

std::vector<managed_bytes_opt> zeros_tuple_elems(columns.size(), managed_bytes_opt(I(0)));
data_type tup_type = tuple_type_impl::get_instance(std::vector<data_type>(columns.size(), int32_type));
::shared_ptr<tuples::value> zeros_tuple =
::make_shared<tuples::value>(std::move(zeros_tuple_elems), std::move(tup_type));
managed_bytes tup_bytes = tuple_type_impl::build_value_fragmented(std::move(zeros_tuple_elems));
constant zeros_tuple(raw_value::make_value(std::move(tup_bytes)), std::move(tup_type));

return binary_operator(column_tuple, oper, zeros_tuple);
return binary_operator(column_tuple, oper, std::move(zeros_tuple));
};

expression pk1_pk2_restriction = make_multi_column_restriction({&col_pk1, &col_pk2}, oper_t::LT);
Expand Down
1 change: 1 addition & 0 deletions types/collection.hh
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#include "schema_fwd.hh"
#include "log.hh"
#include "cql_serialization_format.hh"
#include "exceptions/exceptions.hh"

namespace cql3 {

Expand Down
86 changes: 86 additions & 0 deletions types/map.hh
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,92 @@ public:
cql_serialization_format sf);
static managed_bytes serialize_partially_deserialized_form_fragmented(const std::vector<std::pair<managed_bytes_view, managed_bytes_view>>& v,
cql_serialization_format sf);

// Serializes a map using the internal cql serialization format
// Takes a range of pair<const bytes, bytes>
template <std::ranges::range Range>
requires std::convertible_to<std::ranges::range_value_t<Range>, std::pair<const bytes, bytes>>
static bytes serialize_to_bytes(const Range& map_range);

// Serializes a map using the internal cql serialization format
// Takes a range of pair<const managed_bytes, managed_bytes>
template <std::ranges::range Range>
requires std::convertible_to<std::ranges::range_value_t<Range>, std::pair<const managed_bytes, managed_bytes>>
static managed_bytes serialize_to_managed_bytes(const Range& map_range);
};

data_value make_map_value(data_type tuple_type, map_type_impl::native_type value);

template <std::ranges::range Range>
requires std::convertible_to<std::ranges::range_value_t<Range>, std::pair<const bytes, bytes>>
bytes map_type_impl::serialize_to_bytes(const Range& map_range) {
size_t serialized_len = 4;
size_t map_size = 0;
for (const std::pair<bytes, bytes>& elem : map_range) {
serialized_len += 4 + elem.first.size() + 4 + elem.second.size();
map_size += 1;
}

if (map_size > std::numeric_limits<int32_t>::max()) {
throw exceptions::invalid_request_exception(
fmt::format("Map size too large: {} > {}", map_size, std::numeric_limits<int32_t>::max()));
}

bytes result(bytes::initialized_later(), serialized_len);
bytes::iterator out = result.begin();

write_collection_size(out, map_size, cql_serialization_format::internal());
for (const std::pair<bytes, bytes>& elem : map_range) {
if (elem.first.size() > std::numeric_limits<int32_t>::max()) {
throw exceptions::invalid_request_exception(
fmt::format("Map key size too large: {} bytes > {}", map_size, std::numeric_limits<int32_t>::max()));
}

if (elem.second.size() > std::numeric_limits<int32_t>::max()) {
throw exceptions::invalid_request_exception(
fmt::format("Map value size too large: {} bytes > {}", map_size, std::numeric_limits<int32_t>::max()));
}

write_collection_value(out, cql_serialization_format::internal(), elem.first);
write_collection_value(out, cql_serialization_format::internal(), elem.second);
}

return result;
}

template <std::ranges::range Range>
requires std::convertible_to<std::ranges::range_value_t<Range>, std::pair<const managed_bytes, managed_bytes>>
managed_bytes map_type_impl::serialize_to_managed_bytes(const Range& map_range) {
size_t serialized_len = 4;
size_t map_size = 0;
for (const std::pair<managed_bytes, managed_bytes>& elem : map_range) {
serialized_len += 4 + elem.first.size() + 4 + elem.second.size();
map_size += 1;
}

if (map_size > std::numeric_limits<int32_t>::max()) {
throw exceptions::invalid_request_exception(
fmt::format("Map size too large: {} > {}", map_size, std::numeric_limits<int32_t>::max()));
}

managed_bytes result(managed_bytes::initialized_later(), serialized_len);
managed_bytes_mutable_view out(result);

write_collection_size(out, map_size, cql_serialization_format::internal());
for (const std::pair<managed_bytes, managed_bytes>& elem : map_range) {
if (elem.first.size() > std::numeric_limits<int32_t>::max()) {
throw exceptions::invalid_request_exception(
fmt::format("Map key size too large: {} bytes > {}", map_size, std::numeric_limits<int32_t>::max()));
}

if (elem.second.size() > std::numeric_limits<int32_t>::max()) {
throw exceptions::invalid_request_exception(
fmt::format("Map value size too large: {} bytes > {}", map_size, std::numeric_limits<int32_t>::max()));
}

write_collection_value(out, cql_serialization_format::internal(), elem.first);
write_collection_value(out, cql_serialization_format::internal(), elem.second);
}

return result;
}