Commit Graph

2814 Commits

Author SHA1 Message Date
Avi Kivity
9823e75d16 cql3: grammar: make where clause return an expression
In preparation of the relaxation of the grammar to return any expression,
change the whereClause production to return an expression rather than
terms. Note that the expression is still constrained to be a conjunction
of relations, and our filtering code isn't prepared for more.

Before the patch, if the WHERE clause was optional, the grammar would
pass an empty vector of expressions (which is exactly correct). After
the patch, it would pass a default-constructed expression. Now that
happens to be an empty conjunction, which is exactly what's needed, but
it is too accidental, so the patch changes optional WHERE clauses to
explicitly generate an empty conjunction if the WHERE clause wasn't
specified.
2022-07-22 20:14:48 +03:00
Avi Kivity
a037f9a086 cql3: util: deinline where clause utilities
Some where clause related functions were unnecessarily inline; another
was just recently de-templated. Move them to .cc.
2022-07-22 20:14:48 +03:00
Avi Kivity
fd663bcb94 cql3: util: change where clause utilities to accept a single expression rather than a vector of terms
Conversion to terms happens internally via boolean_factors().
2022-07-22 20:14:48 +03:00
Avi Kivity
a5dd588465 cql3: statement_restrictions: accept a single expression rather than a vector
Move closer to the goal of accepting a generic expression for WHERE
clause by accepting a generic expression in statement_restrictions. The
various callers will synthesize it from a vector of terms.
2022-07-22 20:14:48 +03:00
Avi Kivity
43aca25496 cql3: statement_restrictions: merge if and for
A `for` loop does nothing on an empty container, so no need for an
extra `if` for that condition. Drop the `if`.
2022-07-22 20:14:48 +03:00
Avi Kivity
4aa0a03b7e cql3: select_statement: remove wrong but harmless std::move() in prepare_restrictions
std::move(_where_clause) is wrong, because _where_clause is used later
(when analyzing GROUP BY), but also harmless (because the
statement_restrictions constructor accepts it by const reference).

To avoid confusion in the next patch where we'll pass _where_clause
to a different function, remove the bad std::move() in advance here.
2022-07-22 20:14:48 +03:00
Avi Kivity
8085b9f57a cql3: expr: add boolean_factors() function to factorize an expression
When analyzing a WHERE clause, we want to separate individual
factors (usually relations), and later partition them into
partition key, clustering key, and regular column relations. The
first step is separation, for which this helper is added.

Currently, it is not required since the grammar supplies the
expression in separated form, but this will not work once it is
relaxed to allow any expression in the WHERE clause.

A unit test is added.
2022-07-22 20:14:48 +03:00
Avi Kivity
1efb2fecbe cql3: expression: define operator==() for expressions
This is useful for tests, to check that expression manipulations
yield the expected results.
2022-07-22 20:14:48 +03:00
Avi Kivity
eec441d365 cql3: values: add operator==() for raw_value
This is useful for implementing operator==() for expressions, which in
turn require comparing constants, which contain raw_values.

Note that this is not CQL comparison (that would be implemented
in cql3::expr::evaluate() and would return a CQL boolean, not a C++
boolean, but a traditional C++ value comparison.
2022-07-22 20:13:49 +03:00
Avi Kivity
13a64d8ab2 Merge 'Remove all remaining restrictions classes' from Jan Ciołek
This PR removes all code that used classes `restriction`, `restrictions` and their children.

There were two fields in `statement_restrictions` that needed to be dealt with: `_clustering_columns_restrictions` and `_nonprimary_key_restrictions`.

Each function was reimplemented to operate on the new expression representaiion and eventually these fields weren't needed anymore.

After that the restriction classes weren't used anymore and could be deleted as well.

Now all of the code responsible for analyzing WHERE clause and planning a query works on expressions.

Closes #11069

* github.com:scylladb/scylla:
  cql3: Remove all remaining restrictions code
  cql3: Move a function from restrictions class to the test
  cql3: Remove initial_key_restrictions
  cql3: expr: Remove convert_to_restriction
  cql3: Remove _new from _new_nonprimary_key_restrictions
  cql3: Remove _nonprimary_key_restrictions field
  cql3: Reimplement uses of _nonprimary_key_restrictions using expression
  cql3: Keep a map of single column nonprimary key restrictions
  cql3: Remove _new from _new_clustering_columns_restrictions
  cql3: Remove _clustering_columns_restrictions from statement_restrictions
  cql3: Use a variable instead of dynamic cast
  cql3: Use the new map of single column clustering restrictions
  cql3: Keep a map of single column clustering key restrictions
  cql3: Return an expression in get_clustering_columns_restrctions()
  cql3: Reimplement _clustering_columns_restrictions->has_supporting_index()
  cql3: Don't create single element conjunction
  cql3: Add expr::index_supports_some_column
  cql3: Reimplement has_unrestricted_components()
  cql3: Reimplement _clustering_columns_restrictions->need_filtering()
  cql3: Reimplement num_prefix_columns_that_need_not_be_filtered
  cql3: Use the new clustering restrictions field instead of ->expression
  cql3: Reimplement _clustering_columns_restrictions->size() using expressions
  cql3: Reimplement _clustering_columns_restrictions->get_column_defs() using expressions
  cql3: Reimplement _clustering_columns_restrictions->is_all_eq() using expressions
  cql3: expr: Add has_only_eq_binops function
  cql3: Reimplement _clustering_columns_restrictions->empty() using expressions
2022-07-20 18:01:15 +03:00
Botond Dénes
014c5b56a3 query-result: move last_pos up to query::result
query_result was the wrong place to put last position into. It is only
included in data-responses, but not on digest-responses. If we want to
support empty pages from replicas, both data and digest responses have
to include the last position. So hoist up the last position to the
parent structure: query::result. This is a breaking change inter-node
ABI wise, but it is fine: the current code wasn't released yet.

Closes #11072
2022-07-20 13:28:09 +03:00
Jan Ciolek
599bcd6ea7 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>
2022-07-20 09:10:31 +02:00
Jan Ciolek
b269e5a24d cql3: Remove initial_key_restrictions
initial_key restrictions was a class used by statement_restrictions
to represent empty restrictions of different types and simplify
restriction merging logic. They are not used anymore and can
be removed.

Signed-off-by: Jan Ciolek <jan.ciolek@scylladb.com>
2022-07-20 09:10:31 +02:00
Jan Ciolek
4f92c64e1b cql3: expr: Remove convert_to_restriction
This function isn't used anywhere anymore
and can be removed.

Signed-off-by: Jan Ciolek <jan.ciolek@scylladb.com>
2022-07-20 09:10:31 +02:00
Jan Ciolek
d7e954307f cql3: Remove _new from _new_nonprimary_key_restrictions
The _new prefix was used to distinguish the new field
from the old represenation.

Now the new field has fully replaced the old one
and _new can be removed from its name.

Signed-off-by: Jan Ciolek <jan.ciolek@scylladb.com>
2022-07-20 09:10:31 +02:00
Jan Ciolek
b6ae72f095 cql3: Remove _nonprimary_key_restrictions field
All code that made use of _nonprimary_key_restrictions
has been modified to use _new_nonprimary_key_restrictions
instead.

The field can be removed.

Additionally the old code responsible for adding new restrictions
can be fully removed, everything is now done using add_restriction.

Signed-off-by: Jan Ciolek <jan.ciolek@scylladb.com>
2022-07-20 09:10:31 +02:00
Jan Ciolek
9d1ba07471 cql3: Reimplement uses of _nonprimary_key_restrictions using expression
All parts of the code that use _nonprimary_key_restrictions
are changed to use _new_nonprimary_key_restrictions instead.
I decided not to split this into multiple commits,
as there isn't a lot of changes and they are
analogous to the ones done before for partition
and clustering columns.

Signed-off-by: Jan Ciolek <jan.ciolek@scylladb.com>
2022-07-20 09:10:30 +02:00
Jan Ciolek
2c28554390 cql3: Keep a map of single column nonprimary key restrictions
Keep a map of extracted restrictions for each restricted nonprimar column.
This map will be useful, just like the ones for clustering and partition
columns.

Signed-off-by: Jan Ciolek <jan.ciolek@scylladb.com>
2022-07-20 09:10:30 +02:00
Jan Ciolek
0e8f437f24 cql3: Remove _new from _new_clustering_columns_restrictions
The _new was used to distinguish from the old field
during transition. Now the old field has been deleted
and the new one can take its place.

Signed-off-by: Jan Ciolek <jan.ciolek@scylladb.com>
2022-07-20 09:10:27 +02:00
Jan Ciolek
4fac3be535 cql3: Remove _clustering_columns_restrictions from statement_restrictions
All code using the _clustering_columns_restrictions field
has been modified to instead use _new_clustering_columns_restrictions
expression representation.

The old field can now be removed.

Signed-off-by: Jan Ciolek <jan.ciolek@scylladb.com>
2022-07-20 00:41:22 +02:00
Jan Ciolek
bf3f00413e cql3: Use a variable instead of dynamic cast
There is a dynamic cast used to determine whether
clustering columns are restricted by a multi column
restriction.

Instead of doing that we can just use the _has_multi_column
variable.

It's also used a few lines higher, which means that
it should be already initialized.

Signed-off-by: Jan Ciolek <jan.ciolek@scylladb.com>
2022-07-20 00:41:22 +02:00
Jan Ciolek
a0884760ab cql3: Use the new map of single column clustering restrictions
Signed-off-by: Jan Ciolek <jan.ciolek@scylladb.com>
2022-07-20 00:41:07 +02:00
Jan Ciolek
9a03a09422 cql3: Keep a map of single column clustering key restrictions
Having this map is useful in a bunch of places.

To keep code simple it could be created from scratch each time,
but it's also used in do_filter, so this could actually
affect performance.

Signed-off-by: Jan Ciolek <jan.ciolek@scylladb.com>
2022-07-19 16:02:01 +02:00
Jan Ciolek
2b7ffd57fb cql3: Return an expression in get_clustering_columns_restrctions()
get_clustering_columns_restrctions() used to return
a shared pointer to the clustering_restrictions class.

Now everything is being converted to expression,
so it should return an expression as well.

Signed-off-by: Jan Ciolek <jan.ciolek@scylladb.com>
2022-07-19 16:02:01 +02:00
Jan Ciolek
ebbbc3291a cql3: Reimplement _clustering_columns_restrictions->has_supporting_index()
The code is copied from the corresponding restrictions classes.

Signed-off-by: Jan Ciolek <jan.ciolek@scylladb.com>
2022-07-19 16:01:40 +02:00
Jan Ciolek
991fd5e4db cql3: Don't create single element conjunction
In case the expression is empty and we want to merge it
with a new restriction we can just set the expression
to the new restriction.

Later this will make it easier to distinguish which case
of multi column restrictions are we dealing with.

IN and EQ can only have a single binary operator,
but slice might have two.

Signed-off-by: Jan Ciolek <jan.ciolek@scylladb.com>
2022-07-19 15:38:33 +02:00
Jan Ciolek
c7495fa59e cql3: Add expr::index_supports_some_column
Add a function that checks if there is an index
which supports one of the columns present in
the given expression.

This functionality will soon be needed for
clustering and nonprimary columns so it's
good to separate into a reusable function.

Signed-off-by: Jan Ciolek <jan.ciolek@scylladb.com>
2022-07-19 15:38:20 +02:00
Jan Ciolek
c2d20adc49 cql3: Reimplement has_unrestricted_components()
The code is copied from:
clustering_key_restrictions::has_unrestricted_components

Signed-off-by: Jan Ciolek <jan.ciolek@scylladb.com>
2022-07-18 17:49:23 +02:00
Jan Ciolek
85ebe99eb5 cql3: Reimplement _clustering_columns_restrictions->need_filtering()
The code is copied from:
single_column_primary_key_restrictions<clustering_key>::needs_filtering

Signed-off-by: Jan Ciolek <jan.ciolek@scylladb.com>
2022-07-18 17:49:09 +02:00
Jan Ciolek
d3a2a77b99 cql3: Reimplement num_prefix_columns_that_need_not_be_filtered
The code is copied from:
single_column_primary_key_restrictions<clustering_key>
::num_prefix_columns_that_need_not_be_filtered

Signed-off-by: Jan Ciolek <jan.ciolek@scylladb.com>
2022-07-18 17:48:55 +02:00
Jan Ciolek
1914d21f7b cql3: Use the new clustering restrictions field instead of ->expression
Instead of writing
_clustering_columns_restrictions->expression
It's better to use the new field:
_new_clustering_columns_restrictions

These expressions should be the same.
It removes another use of the unwanted restrictions field.

Signed-off-by: Jan Ciolek <jan.ciolek@scylladb.com>
2022-07-18 17:48:36 +02:00
Jan Ciolek
360087c580 cql3: Reimplement _clustering_columns_restrictions->size() using expressions
Signed-off-by: Jan Ciolek <jan.ciolek@scylladb.com>
2022-07-18 17:46:14 +02:00
Jan Ciolek
92df275868 cql3: Reimplement _clustering_columns_restrictions->get_column_defs() using expressions
Signed-off-by: Jan Ciolek <jan.ciolek@scylladb.com>
2022-07-18 17:45:50 +02:00
Jan Ciolek
88da7ae0dc cql3: Reimplement _clustering_columns_restrictions->is_all_eq() using expressions
Use the freshly added function to replace old calls to ->is_all_eq().

Signed-off-by: Jan Ciolek <jan.ciolek@scylladb.com>
2022-07-18 17:45:35 +02:00
Jan Ciolek
6cf0981aa6 cql3: expr: Add has_only_eq_binops function
Add a function which checks that an expression
contains only binary operators with '='.

Right now this check is done only in a single place,
but soon the same check will have to be done
for clustering columns as well, so the code
is moved to a separate function to prevent duplication.

Signed-off-by: Jan Ciolek <jan.ciolek@scylladb.com>
2022-07-18 17:45:06 +02:00
Jan Ciolek
b84787efac cql3: Reimplement _clustering_columns_restrictions->empty() using expressions
All occurences of _clustering_columns_restrictions->empty()
have been replaced with code that operates on the new
expression representation: _new_clustering_columns_restrictions.

Signed-off-by: Jan Ciolek <jan.ciolek@scylladb.com>
2022-07-18 17:44:50 +02:00
Jadw1
182438c5f8 forward_service: enable multiple selection
Enables parallelization of query like `SELECT MIN(x), MAX(x)`.
Compatibility is ensured under the same cluster feature as
UDA and native aggregates parallelization. (UDA_NATIVE_PARALLELIZED_AGGREGATION)
2022-07-18 15:25:41 +02:00
Jadw1
29a0be75da forward_service: support UDA and native aggregate parallelization
Enables parallelization of UDA and native aggregates. The way the
query is parallelized is the same as in #9209. Separate reduction
type for `COUNT(*)` is left for compatibility reason.
2022-07-18 15:25:41 +02:00
Jadw1
a0a6d87c1b cql3:functions: Add cql3::functions::functions::mock_get()
`mock_get` was created only for forward_service use, thus it only checks for
aggregate functions if no declared function was found.

The reason for this function is, there is no serialization of `cql3::selection::selection`,
so functions lying underneath these selections has to be refound.

Most of this code is copied from `functions::get()`, however `functions::get()` is not used because it requires to
mock or serialize expressions and `functions::find()` is not enough,
because it does not search for dynamic aggregate functions
2022-07-18 15:25:41 +02:00
Jadw1
6d977fcf88 cql3: selection: detect parallelize reduction type
Detects type of reduction if it is possible. Separate case for
`COUNT(*)` is left for compatibility reason. By now only single
selection is supported.
2022-07-18 15:25:41 +02:00
Jadw1
59498caeca db,cql3: Move part of cql3's function into db
Moving `function`, `function_name` and `aggregate_function` into
db namespace to avoid including cql3 namespace into query-request.
For now, only minimal subset of cql3 function was moved to db.
2022-07-18 15:25:41 +02:00
Jadw1
6b63417bc8 selection: detect if selectors factory contains only simple selectors
Because `selection` is not serializable and it has to be send via network
to parallelize query, we have to mock the selection. To simplify
the mocking, for now only single selectors for aggregate's arguments
are allowed (no casting or other functions as arguments).
2022-07-18 15:25:41 +02:00
Jadw1
0f08c8e099 cql3: reducible aggregates
Introduces reducible aggregates which don't return final result
but accumulator, that can be later reduced.
2022-07-18 15:25:41 +02:00
Jadw1
d13f347621 DB: Add scylla_aggregates system table
Saving information about UDA's reduce function to `scylla_aggregates`
table and distributing it across cluster.
2022-07-18 15:25:37 +02:00
Jadw1
d8f3461147 CQL3: Add reduce function to UDA
Add optional field to UDA, that describes reduce function to allow
parallelization of UDA aggregates.
2022-07-18 14:18:48 +02:00
Jan Ciolek
38e115edf7 cql3: Move single element IN restrictions handling
Restrictions like
col IN (1)
get converted to
col = 1
as an optimization/simplification.

This used to be done in prepare_binary_operator,
but it fits way better inside of
validate_and_prepare_new_restriction.

When it was being done in prepare_binary_operator
the conversion happened before validation checks
and the error messages would describe an equality
restriction despite the user making an IN restriction.

Now the conversion happens after all validation
is finished, which ensures that all checks are
being done on the original expression.

Fixes: #10631

Signed-off-by: Jan Ciolek <jan.ciolek@scylladb.com>
2022-07-11 15:47:16 +02:00
Jan Ciolek
cb504b2d6e cql3: Check for disallowed operators early
Move checking for disallowed operators
earlier in the code flow.
This is needed to pass some tests that
expect one error message instead of the other.

Signed-off-by: Jan Ciolek <jan.ciolek@scylladb.com>
2022-07-11 15:47:16 +02:00
Jan Ciolek
62155846bc cql3: Simplify adding restrictions
The code that adds restrictions in statement_restrictions.cc
is unnecessarily convoluted.

The code to handle IS NOT NULL is actually repeated twice,
once in the constructor and once in add_is_not_restriction.
I missed this when I orignally modified this code.
There is no need to keep duplicate code, we can just
use the new add_is_not_restriction.

Signed-off-by: Jan Ciolek <jan.ciolek@scylladb.com>
2022-07-11 15:47:16 +02:00
Jan Ciolek
debd7399fd cql3: Reorganize to_restriction code
expr::to_restriction is currently used to
take a restriction from the WHERE clause,
prepare it, perform some validation checks
and finally convert it to an instance of
the restriction class.

Soon we will get rid of the restriction class.

In preparation for that expr::to_restriction
is split into two independent parts:
* The part that prepares and validates a binary_operator
* The part that converts a binary_operator to restriction

Thanks to this split getting rid of restriction class
will be painless, we will just stop using the
second part.

This commit splits expr::to_restriction into two functions;
* validate_and_prepare_new_restriction
* convert_to_restriction
that handle each of those parts.

All helper validation methods in the anonymous namespace
are copied from the to_restriction.cc file.

to_restriction.cc isn't the best filename for the new functionality,
so it has been renamed to restrictions.hh/cc.
In the future all the code regarding restrictions could be
put there to reduce clutter in expression.hh/cc

Signed-off-by: Jan Ciolek <jan.ciolek@scylladb.com>
2022-07-11 15:47:16 +02:00
Jan Ciolek
5be574fe51 cql3: Fix IS NOT NULL check in to_restriction
expr::to_restriction performs a check to see if
the restriction is of form: `col IS NOT NULL`

There is a mistake in this check.
It uses is<null>(prepared_binop.rhs)
to determine if the right hand side of binary operator
is a null, but the binary operator is already prepared.

During preparation expr::null is converted to expr::constant
and that wouldn't be detected by this check.

The check has been changed to check for null constant instead
of expr::null.

Signed-off-by: Jan Ciolek <jan.ciolek@scylladb.com>
2022-07-11 15:47:15 +02:00