Commit Graph

72 Commits

Author SHA1 Message Date
Avi Kivity
8c0f2f9e3d Revert "Merge 'cql3: Add expr::constant to replace terminal' from Jan Ciołek"
This reverts commit e9343fd382, reversing
changes made to 27138b215b. It causes a
regression in v2 serialization_format support:

collection_serialization_with_protocol_v2_test fails with: marshaling error: read_simple_bytes - not enough bytes (requested 1627390306, got 3)

Fixes #9360
2021-09-20 15:15:09 +03:00
Jan Ciolek
a0ec2113ae cql3: Replace most uses of terminal with expr::constant
constant is now ready to replace terminal as a final value representation.
Replace bind() with evaluate and shared_ptr<terminal> with constant.

We can't get rid of terminal yet. Sometimes terminal is converted back
to term, which constant can't do. This won't be a problem once we
replace term with expression.

Signed-off-by: Jan Ciolek <jan.ciolek@scylladb.com>
2021-09-13 17:47:17 +02:00
Jan Ciolek
b67f72037f cql3: expr: Remove repetition from expr::get_elements
There was some repeating code in expr::get_elements family
of functions. It has been reduced into one function.

Signed-off-by: Jan Ciolek <jan.ciolek@scylladb.com>
2021-09-13 17:47:17 +02:00
Jan Ciolek
8b475a966c cql3: expr: Add expr::get_elements(constant)
We need to be able to access elements of a constant.
Adds functions to easily do it.

Those functions check all preconditions required to access elements
and then use partially_deserialize_* or similar.

It's much more convenient than using partially_deserialize directly.

get_list_of_tuples_elements is useful with IN restrictions like
(a, b) IN [(1, 2), (3, 4)].

Signed-off-by: Jan Ciolek <jan.ciolek@scylladb.com>
2021-09-13 17:47:17 +02:00
Jan Ciolek
c3fb2f2b57 cql3: Replace all uses of bind_and_get with evaluate_to_raw_view
Start using evaluate_to_raw_value instead of bind_and_get.
This is a step towards using only evaluate.

Signed-off-by: Jan Ciolek <jan.ciolek@scylladb.com>
2021-09-13 17:44:06 +02:00
Jan Ciolek
25caa1950d cql3: expr: Add evaluate_IN_list
A list representing IN values might contain NULLs before evaluation.
We can remove them during evaluation, because nothing equals NULL.
If we don't remove them, there are gonna be errors, because a list can't contain NULLs.

Signed-off-by: Jan Ciolek <jan.ciolek@scylladb.com>
2021-09-13 17:03:23 +02:00
Jan Ciolek
844bf2d472 cql3: expr: Add expr::evaluate
Adds the functions:
constant evaluate(term*, const query_options&);
raw_value_view evaluate(term*, const query_options&);

These functions take a term, bind it and convert the terminal
to constant or raw_value_view.

In the future these functions will take expression instead of term.
For that to happen bind() has to be implemented on expression,
this will be done later.

Also introduces terminal::get_value_type().
In order to construct a constant from terminal we need to know the type.
It will be implemented in the following commits.

Signed-off-by: Jan Ciolek <jan.ciolek@scylladb.com>
2021-09-13 17:03:23 +02:00
Jan Ciolek
79cb268ada cql3: expr: Add constant to expression
Adds constant to the expression variant:
struct constant {
    raw_value value;
    data_type type;
};

This struct will be used to represent constant values with known bytes and type.
This corresponds to the terminal from current design.

bool is removed from expression, now constant is used instead.

Signed-off-by: Jan Ciolek <jan.ciolek@scylladb.com>
2021-09-13 17:03:21 +02:00
Avi Kivity
7a798b44a2 cql3: expr: replace column_value_tuple by a composition of tuple_constructor and column_value
column_value_tuple overlaps both column_value and tuple_constructor
(in different respects) and can be replaced by a combination: a
tuple_constructor of column_value. The replacement is more expressive
(we can have a tuple of column_value and other expression types), though
the code (especially grammar) do not allow it yet.

So remove column_value_tuple and replace it everywhere with
tuple_constructor. Visitors get the merged behavior of the existing
tuple_constructor and column_value_tuple, which is usually trivial
since tuple_constructor and column_value_tuple came from different
hierarchies (term::raw and relation), so usually one of the types
just calls on_internal_error().

The change results in awkwards casts in two areas: WHERE clause
filtering (equal() and related), and clustering key range evaluations
(limits() and related). When equal() is replaced by recursive
evaluate(), the casts will go way (to be replaced by the evaluate())
visitor. Clustering key range extraction will remain limited
to tuples of column_value, so the prepare phase will have to vet
the expressions to ensure the casts don't fail (and use the
filtering path if they will).

Tests: unit (dev)

Closes #9274
2021-09-10 10:43:29 +02:00
Nadav Har'El
9666921dbc Merge 'cql3: expr: introduce search_and_replace()' from Avi Kivity
Introduce a general-purpose search and replace function to manipulate
expressions, and use it to simplify replace_column_def() and
replace_token().

Closes #9259

* github.com:scylladb/scylla:
  cql3: expr: rewrite replace_token in terms of search_and_replace()
  cql3: expr: rewrite replace_column_def in terms of search_and_replace()
  cql3: expr: add general-purpose search-and-replace
2021-08-31 15:56:41 +03:00
Avi Kivity
542a8bc0f3 cql3: expr: rewrite replace_token in terms of search_and_replace()
Use search_and_replace() to simplify replace_token(). Note the conversion
does not have 100% fidelity - the previous implementation throws on
some impossible subexpression types, and the new one passes them
through. It should be the caller's responsibility anyway, not a
side effect of replacing tokens, and since these subexpressions are
impossible there is no real effect on execution.

Note that this affects only TOKEN() calls on the partition key
columns in the right order. Other uses of the token function
(say with constants) won't be translated to the token subexpression
type. So something like

    WHERE token(pk) = token(?)

would only see the left-hand side replaced, not the right-hand
side, even if it were an expression rather than a term.
2021-08-31 12:29:47 +03:00
Avi Kivity
10ca63128a cql3: expr: rewrite replace_column_def in terms of search_and_replace()
We're won't introduce new expression types that are equivalent
to column_value, and search_and_replace() takes care of all
expressions that need to recurse, so we don't need std::visit()
for the search/replace lambda.
2021-08-31 12:29:47 +03:00
Avi Kivity
7a594bc42f cql3: expr: add general-purpose search-and-replace
Add a recursive search-and-replace function on expressions. The
caller provides a search/replace function to operate on subexpressions,
returning nullopt if they want the default behavior of recursively
copying, or a new expression to terminate the search (in the current
subtree) and replace the current node with the returned expression.

To avoid endlessly specifying the subexpression types that get the
the common behavior (copying) since they don't contain any subexpressions,
we add a new concept LeafExpression to signify them.

Existing functions such as replace_token() can be reimplemented in
terms of search_and_replace, but that is left for later.
2021-08-31 12:29:37 +03:00
Dejan Mircevski
81f00d82cf cql3: Drop more dead code
This is some dead code that 44ca965ba missed.

Tests: unit (dev)

Signed-off-by: Dejan Mircevski <dejan@scylladb.com>

Closes #9267
2021-08-31 12:06:19 +03:00
Avi Kivity
158822c1a6 cql3: term::raw: remove term::raw and scaffolding
Nothing now uses term::raw, remove it and the scaffolding used to
migrate it to expressions.
2021-08-26 16:14:47 +03:00
Avi Kivity
562e68835b cql3: expr, user types: convert user type literals to expressions
Convert the user_types::literal raw to a new expression type
usertype_constructor. I used "usertype" to convey that is is a
((user type) constructor), not a (user (type constructor)).
2021-08-26 15:26:35 +03:00
Avi Kivity
06bca067f8 cql3: expr, sets, maps: convert set and map literals to collection_constructor
Add set and map styles to collection_constructor. Maps are implemented as
collection_constructor{tuple_constructor{key, value}...}. This saves
having a new expression type, and reduces the effort to implement
recursive descent evaluation for this omitted expression type.
2021-08-26 15:13:37 +03:00
Avi Kivity
d2ab7fc26d cql3: expr, lists: convert lists::literal to new collection_constructor
Introduce a collection_constructor (similar to C++'s std::initializer_list)
to hold subexpressions being gathered into a list. Since sets, maps, and
lists construction share some attributes (all elements must be of the
same type) collection_constructor will be used for all of them, so it
also holds an enum. I used "style" for the enum since it's a weak
attribute - an empty set is also an empty map. I chose collection_constructor
rather than plain 'collection' to highlight that it's not the only way
to get a collection (selecting a collection column is another, as an
example) and to hint at what it does - construct a collection from
more primitive elements.
2021-08-26 15:10:41 +03:00
Avi Kivity
5e448e4a2a cql3: tuples, expr: convert tuples::literal to expr::tuple_constructor
Introduce tuple_constructor (not a literal, since (?, ?) and (column_value,
column_value) are not literals) to represent a tuple constructed from
subexpressions. In the future we can replace column_value_tuple
with tuple_constructor(column_value, column_value, ...), but this is
not done now.

I chose the name 'tuple_constructor' since other expressions can represent
tuples (e.g. my_tuple_column, :bind_variable_of_tuple_type,
func_returning_tuple()). It also explains what the expression does.
2021-08-26 15:07:15 +03:00
Avi Kivity
2c42a65db1 cql3: expr, constants: convert constants::literal to untyped_constant
Introduce a new expression untyped_constant that corresponds to
constants::literal, which is removed. untyped_constant is rather
ugly in that it won't exist post-prepare. We should probably instead
replace it with typed constants that use the widest possible type
(decimal and varint), and select a narrower type during the prepare
phase when we perform type inference. The conversion itseld is
straightforward.
2021-08-26 15:03:07 +03:00
Avi Kivity
838bfbd3e0 cql3: expr, abstract_marker: convert to expressions
Convert the four forms of abstract_marker to expr::bind_variable (the
name was chosen since variable is the role of the thing, while "marker"
refers more to the grammar). Having four variants is unnecessary, but
this patch doesn't do anything about that.
2021-08-26 15:01:04 +03:00
Avi Kivity
aba205917d cql3: expr, constants: convert cql3::constants::null_literal to new cql3::expr::null
Introduce cql3::expr::null and use it to represent null_literal, which is
removed.
2021-08-26 14:49:46 +03:00
Avi Kivity
3d30c161e4 cql3: expr: prepare expr::cast for unprepared types
The cast expression has two operands: the subexpression to cast and the
type to cast to. Since prepared and unprepared expressions are the
same type, we don't have to do anything, but prepared and unprepared
types are different. So add a variant to be able to support both.

The reason the selectable->expression transformation did not need to
do this is that casts in a selector cannot accept a user defined type.
Note those casts also have different syntax and different execution,
so we'll have to choose whether to unify the two semantics, or whether
to keep them separate. This patch does not force anything (but does hint
at unification by not including any discriminant beyond the type's
rawness). The string representation matches the part of the grammar
it was derived from (or conversion back to CQL will yield wrong
results).
2021-08-26 14:39:33 +03:00
Avi Kivity
0d24af7775 cql3: expr, term::raw: add conversions between the two types
Add a way to convert between the old world and the new, and back. Note
that instead of blindly wrapping, we unwrap if we received a wrapped
object.
2021-08-26 14:35:46 +03:00
Avi Kivity
a5031dd5bf cql3: expr, term::raw: add reverse bridge
Since expressions can nest, and since we won't covert everything at once,
add a way to store a term::raw as an expression. We can now have a
term::raw that is internally an expression, and an expression that is
implemented as term::raw.
2021-08-26 14:32:04 +03:00
Avi Kivity
725065b066 cql3: term::raw, expr: add bridge between term::raw and expressions
A term_raw_expression is a term::raw that holds an expression. It will
be used to incrementally convert the source base to expressions, while
still exposing the result to the common interface of shared_ptr<term::raw>.
2021-08-26 14:14:18 +03:00
Jan Ciolek
a7d1dab066 statement_restrictions_test: tests for extracting column restrictions
Add unit tests for the function
extract_single_column_restrictions_for_column()

Signed-off-by: Jan Ciolek <jan.ciolek@scylladb.com>
2021-08-02 15:43:42 +02:00
Jan Ciolek
43ab3d6831 expression: add a function to extract restrictions for a column
Add a function, which given an expression and a column,
extracts all restrictions involving this column.

Signed-off-by: Jan Ciolek <jan.ciolek@scylladb.com>
2021-08-02 15:43:33 +02:00
Avi Kivity
2b7b9bb469 cql3: expressions: fix printing of nested expressions
Now that we eliminated cql3::selectable::raw, we can print
nested expressions.
2021-07-27 20:16:29 +03:00
Avi Kivity
979010a1e5 cql3: expression: convert selectable::with_field_selection::raw to expression
Add a field_selection variant element to expression. Like function_call
and cast, the structure from which a field is selectewd cannot yet be
an expression, since not all seletable::raw:s are converted. This will
be done in a later pass. This is also why printing a field selection now
does not print the selected expression; this will also be corrected later.
2021-07-27 20:16:12 +03:00
Avi Kivity
714b812212 cql3: expression: convert selectable::with_cast::raw to expression
Add a cast variant element to expression. Like function_call, the
argument being converted cannot yet be an expression, since not
all seletable::raw:s are converted. This will be done in a later
pass.  This is also why printing a cast now does not print the
casted expression; this will also be corrected later.
2021-07-27 20:14:52 +03:00
Avi Kivity
5adae5837e cql3: expression: convert selectable::with_anonymous_function::raw to expression
Rather than creating a new variant element in expression, we extend
function_call to handle both named and anonymous functions, since
most of the processing is the same.
2021-07-27 20:13:55 +03:00
Avi Kivity
3e392d2513 cql3: expression: convert selectable::with_function_call::raw to expressions
Add a function_call variant element to hold function calls. Note
that because not all selectables are yet converted, function call
arguments are still of type selectable::raw. They will be converted
to expressions later. This is also why printing a function now
does not print its arguments; this will also be corrected later.
2021-07-27 20:13:51 +03:00
Avi Kivity
ff65c54316 cql3: expressions: convert writetime_or_ttl::raw to expression
Create a new element in the expression variant, column_mutation_attribute,
signifying we're picking up an attribute of a column mutation (not a
column value!). We use an enum rather than a bool to choose between
writetime and ttl (the two mutation attributes) for increased
explicitness.

Although there can only be one type for the column we're operating
on (it must be an unresolved_identifer), we use a nested_expression.
This is because we'll later need to also support a column_value
as the column type after we prepare it. This is somewhat similar
to the address of operator in C, which syntactically takes any
expression but semantically operates only on lvalues.
2021-07-27 20:10:52 +03:00
Avi Kivity
ac3b093e3c cql3: expression: use nested_expression in binary_operator
binary_operator::lhs is implementing the pattern in nested_expression.
Use nested_expression instead to reduce code size.
2021-07-27 20:08:34 +03:00
Avi Kivity
b07a0867b3 cql3: expression: introduce nested_expression class
The exression type cannot be a member of a struct that is an
element of the expression variant. This is because it would then
be required to contain itself. So introduce a nested_expression
type to indirectly hold an expression, but keep the value semantics
we expect from expressions: it is copyable and a copy has separate
identity and storage.

In fact binary_operator had to resort to this trick, so it's converted
to nested_expression in the next patch.
2021-07-27 20:08:21 +03:00
Avi Kivity
8a518e9c78 Convert column_identifier_raw's use as selectable to expressions
Introduce unresolved_identifer as an unprepared counterpart to column_value.
column_identifier_raw no longer inherits from selectable::raw, but
methods for now to reduce churn.
2021-07-27 20:08:15 +03:00
Jan Ciolek
51ee9adeec expression: Add replace_token function
Adds replace_token function which takes an expression
and replaces all left hand side occurences of token()
with the given column definition.

Signed-off-by: Jan Ciolek <jan.ciolek@scylladb.com>
2021-07-21 12:25:12 +02:00
Piotr Sarna
1e0880e345 cql3,expr: unify get_value
Now that there's only one helper function for getting values,
the call can be inlined instead.
2021-07-13 10:40:08 +02:00
Piotr Sarna
95002bb8d4 cql3,expr: purge mutation-based is_satisfied_by
The interface is now unified, and all callers use the original
CQL3-backed API.
2021-07-13 10:40:08 +02:00
Avi Kivity
3c21833aac cql3: expr: make column_value (and similar) a first-class expression
Currently, column names can only appear in a boolean binary expression,
but not on their own. This means that in the statement

   SELECT a FROM tab WHERE a > 3;

We can represent the WHERE clause as an expression, but not the selector.

To pave the way for using expressions in selector contexts, we promote
the elements of binary_operator::lhs (column_value, column_value_tuple,
token) to be expressions in their own right. binary_operator::lhs
becomes an expression (wrapped in unique_ptr, because variants can't
contain themselves).

Note that all three new possibilities make sense in a selector:

  SELECT column FROM tab
  SELECT token(pk) FROM tab
  SELECT function_that_accepts_a_tuple((col1, col2)) FROM tab

There is some fallout from this:

 - because binary_operator contains a unique_ptr, it is no longer
   copyable. We add a copy constructor and assignment operator to
   compensate.
 - often, the new elements don't make sense when evaluating a boolean
   expression, which is the only context we had before. We call
    on_internal_error in these cases. The parser right now prevents such
   cases from being constructed in the first place (this is equivalent to
   if (some_struct_value) in C).
 - in statement_restrictions.cc, we need to evalute the lhs in the context
   of the full binary operator. I introduced with_current_binary_operator()
   for this; an alternative approach is to create a new sub-visitor.

Closes #8797
2021-06-17 10:08:58 +03:00
Pavel Solodovnikov
76bea23174 treewide: reduce header interdependencies
Use forward declarations wherever possible.

Signed-off-by: Pavel Solodovnikov <pa.solodovnikov@scylladb.com>

Closes #8813
2021-06-07 15:58:35 +03:00
Avi Kivity
a55b434a2b treewide: extent copyright statements to present day 2021-06-06 19:18:49 +03:00
Avi Kivity
8a4abe9895 cql3: expression: don't copy expression in has_supporting_index()
std::bind() copies the bound parameters for safekeeping. Here this
includes expr, which can be quite heavyweight. Use std::ref() to
prevent copying. This is safe since the bound expression is executed
and discarded before has_supporting_index() returns.

Closes #8791
2021-06-06 19:18:49 +03:00
Pavel Solodovnikov
fff7ef1fc2 treewide: reduce boost headers usage in scylla header files
`dev-headers` target is also ensured to build successfully.

Signed-off-by: Pavel Solodovnikov <pa.solodovnikov@scylladb.com>
2021-05-20 01:33:18 +03:00
Avi Kivity
bd16e98019 expr: give a name to a tuple of columns
Right now, binary_operator::lhs is a variant<column_value,
std::vector<column_value>, token>. The role of the second branch
(a vector of column values) is to represent a tuple of columns
e.g. "WHERE (a, b, c) = ?"), but this is not clear from the type
name.

Inroduce a wrapper type around the vector, column_value_tuple, to
make it clear we're dealing with tuples of CQL references (a
column_value is really a column_ref, since it doesn't actually
contain any value).

Closes #8208
2021-04-12 09:40:16 +02:00
Michał Chojnowski
979666075f cql3: expression: use managed_bytes instead of bytes where possible 2021-04-01 10:44:21 +02:00
Michał Chojnowski
6e7e795dfd cql3: expr: expression: make the argument of to_range a forwarding reference
Make to_range able to handle rvalues. We will pass managed_bytes&& to it
in the next patch to avoid pointless copying.
The public declaration of to_range is changed to a concrete function to avoid
having to explicitly instantiate to_range for all possible reference types of
clustering_key_prefix.
2021-04-01 10:44:21 +02:00
Michał Chojnowski
0bb959e890 cql3: don't linearize elements of lists, tuples, and user types
This patch switches the type used to store collection elements inside the
intermediate form used in lists::value, tuples::value etc. from bytes
to managed_bytes. After this patch, tuple and list elements are only linearized
in from_serialized, which will be corrected soon.
This commit introduces some additional copies in expression.cc, which
will be dealt with in a future commit.
2021-04-01 10:44:21 +02:00
Michał Chojnowski
b9322a6b71 cql3: switch users of cql3::raw_value_view to internals-independent API
We want to change the internals of cql3::raw_value{_view}.
However, users of cql3::raw_value and cql3::raw_value_view often
use them by extracting the internal representation, which will be different
after the planned change.

This commit prepares us for the change by making all accesses to the value
inside cql3::raw_value(_view) be done through helper methods which don't expose
the internal representation publicly.

After this commit we are free to change the internal representation of
raw_value_{view} without messing up their users.
2021-04-01 10:42:04 +02:00