Commit Graph

242 Commits

Author SHA1 Message Date
Kefu Chai
2dbf044b91 cql3: do not include unused headers
these unused includes were identified by clangd. see
https://clangd.llvm.org/guides/include-cleaner#unused-include-warning
for more details on the "Unused include" warning.

Signed-off-by: Kefu Chai <kefu.chai@scylladb.com>

Closes scylladb/scylladb#16791
2024-01-16 16:43:17 +02:00
Sylwia Szunejko
91a5a41313 add a way to negotiate generation of the tablet info for drivers
Tablets metadata is quite expensive to generate (each data_value is
an allocation), so an old driver (without support for tablets) will
generate huge amounts of such notifications. This commit adds a way
to negotiate generation of the notification: a new driver will ask
for them, and an old driver won't get them. It uses the
OPTIONS/SUPPORTED/STARTUP protocol described in native_protocol_v4.spec.

Closes scylladb/scylladb#16611
2024-01-02 20:00:50 +02:00
sylwiaszunejko
cea4c40685 cql3: send tablet if wrong node/shard is used during modification statement 2023-11-22 09:23:43 +01:00
Gleb Natapov
4ffc39d885 cql3: Extend the scope of group0_guard during DDL statement execution
Currently we hold group0_guard only during DDL statement's execute()
function, but unfortunately some statements access underlying schema
state also during check_access() and validate() calls which are called
by the query_processor before it calls execute. We need to cover those
calls with group0_guard as well and also move retry loop up. This patch
does it by introducing new function to cql_statement class take_guard().
Schema altering statements return group0 guard while others do not
return any guard. Query processor takes this guard at the beginning of a
statement execution and retries if service::group0_concurrent_modification
is thrown. The guard is passed to the execute in query_state structure.

Fixes: #13942

Message-ID: <ZNsynXayKim2XAFr@scylladb.com>
2023-08-17 15:52:48 +03:00
Avi Kivity
d57a951d48 Revert "cql3: Extend the scope of group0_guard during DDL statement execution"
This reverts commit 70b5360a73. It generates
a failure in group0_test .test_concurrent_group0_modifications in debug
mode with about 4% probability.

Fixes #15050
2023-08-15 00:26:45 +03:00
Gleb Natapov
70b5360a73 cql3: Extend the scope of group0_guard during DDL statement execution
Currently we hold group0_guard only during DDL statement's execute()
function, but unfortunately some statements access underlying schema
state also during check_access() and validate() calls which are called
by the query_processor before it calls execute. We need to cover those
calls with group0_guard as well and also move retry loop up. This patch
does it by introducing new function to cql_statement class take_guard().
Schema altering statements return group0 guard while others do not
return any guard. Query processor takes this guard at the beginning of a
statement execution and retries if service::group0_concurrent_modification
is thrown. The guard is passed to the execute in query_state structure.

Fixes: #13942

Message-ID: <ZNSWF/cHuvcd+g1t@scylladb.com>
2023-08-13 14:19:39 +03:00
Jan Ciolek
bfbc3d70b7 modification_statement: reject conditional statements with empty clustering key
`modification_statement::execute_with_condition` validates that a query with
an IF condition can be executed correctly.

There's already a check for empty partition key ranges, but there was no check
for empty clustering ranges.

Let's add a check for the clustering ranges as well, they're not allowed to be empty.
After this change Scylla outputs the same type of message for empty partition and
clustering ranges, which improves UX.

Signed-off-by: Jan Ciolek <jan.ciolek@scylladb.com>
2023-06-28 10:30:52 +02:00
Kamil Braun
e6942d31d3 Merge 'query processor code cleanup' from Gleb
The series contains mostly cleanups for query processor and no functional
change. The last patch is a small cleanup for the storage_proxy.

* 'qp-cleanup' of https://github.com/gleb-cloudius/scylla:
  storage_proxy: remove unused variable
  client_state: co-routinise has_column_family_access function
  query_processor: get rid of internal_state and create individual query_satate for each request
  cql3: move validation::validate_column_family from client_state::has_column_family_access
  client_state: drop unneeded argument from has.*access functions
  cql3: move check for dropping cdc tables from auth to the drop statement code itself
  query_processor: co-routinise execute_prepared_without_checking_exception_message function
  query_processor: co-routinize execute_direct_without_checking_exception_message function
  cql3: remove empty statement::validate functions
  cql3: remove empty function validate_cluster_support
  cql3/statements: fix indentation and spurious white spaces
  query_processor: move statement::validate call into execute_with_params function
  query_processor: co-routinise execute_with_params function
  query_processor: execute statement::validate before each execution of internal query instead of only during prepare
  query_processor: get rid of shared internal_query_state
  query_processor: co-routinize execute_paged_internal function
  query_processor: co_routinize execute_batch_without_checking_exception_message function
  query_processor: co-routinize process_authorized_statement function
2023-06-23 10:32:57 +02:00
Avi Kivity
b858a4669d cql3: expr: break up expression.hh header
Adding a function declaration to expression.hh causes many
recompilations. Reduce that by:

 - moving some restrictions-related definitions to
   the existing expr/restrictions.hh
 - moving evaluation related names to a new header
   expr/evaluate.hh
 - move utilities to a new header
   expr/expr-utilities.hh

expression.hh contains only expression definitions and the most
basic and common helpers, like printing.
2023-06-22 14:21:03 +03:00
Gleb Natapov
4bad482e4b cql3: move validation::validate_column_family from client_state::has_column_family_access
Checking keyspace/table presence should not be part of authorization code
and it is not done consistently today.  For instance keyspace presence
is not checked in "alter keyspace" during authorization, but during
statement execution. Make it consistent.
2023-06-22 13:57:36 +03:00
Avi Kivity
32b27d6a08 cql3: expr: change evaluation_input vector components to take spans
Spans are slightly cleaner, slightly faster (as they avoid an indirection),
and allow for replacing some of the arguments with small_vector:s.

Closes #14313
2023-06-22 11:28:01 +02:00
Avi Kivity
b7a90d51d2 cql3: add checks for aggregation functions after prepare
Since we don't yet prepare selectors, all calls to prepare_expr()
are adjusted.

Note that missing a check isn't fatal - it will be trapped at runtime
because evaluate(aggregate) will throw.
2023-06-13 21:04:49 +03:00
Jan Ciolek
90b3b85bd0 cql3: use statement_restrictions::has_token_restrictions() wherever possible
The statement_restrictions class has a method called has_token_restriction().
This method checks whether the partition key restrictions contain expr::token.

Let's use this function in all applicable places instead of manually calling has_token().

In the future has_token() will have an additional schema argument,
so eliminating calls to has_token() will simplify the transition.

Signed-off-by: Jan Ciolek <jan.ciolek@scylladb.com>
2023-04-29 13:04:52 +02:00
Kefu Chai
c37f4e5252 treewide: use fmt::join() when appropriate
now that fmtlib provides fmt::join(). see
https://fmt.dev/latest/api.html#_CPPv4I0EN3fmt4joinE9join_viewIN6detail10iterator_tI5RangeEEN6detail10sentinel_tI5RangeEEERR5Range11string_view
there is not need to revent the wheel. so in this change, the homebrew
join() is replaced with fmt::join().

as fmt::join() returns an join_view(), this could improve the
performance under certain circumstances where the fully materialized
string is not needed.

please note, the goal of this change is to use fmt::join(), and this
change does not intend to improve the performance of existing
implementation based on "operator<<" unless the new implementation is
much more complicated. we will address the unnecessarily materialized
strings in a follow-up commit.

some noteworthy things related to this change:

* unlike the existing `join()`, `fmt::join()` returns a view. so we
  have to materialize the view if what we expect is a `sstring`
* `fmt::format()` does not accept a view, so we cannot pass the
  return value of `fmt::join()` to `fmt::format()`
* fmtlib does not format a typed pointer, i.e., it does not format,
  for instance, a `const std::string*`. but operator<<() always print
  a typed pointer. so if we want to format a typed pointer, we either
  need to cast the pointer to `void*` or use `fmt::ptr()`.
* fmtlib is not able to pick up the overload of
  `operator<<(std::ostream& os, const column_definition* cd)`, so we
  have to use a wrapper class of `maybe_column_definition` for printing
  a pointer to `column_definition`. since the overload is only used
  by the two overloads of
  `statement_restrictions::add_single_column_parition_key_restriction()`,
  the operator<< for `const column_definition*` is dropped.

Signed-off-by: Kefu Chai <kefu.chai@scylladb.com>
2023-03-16 20:34:18 +08:00
Nadav Har'El
a4a318f394 cql: USING TTL 0 means unlimited, not default TTL
Our documentation states that writing an item with "USING TTL 0" means it
should never expire. This should be true even if the table has a default
TTL. But Scylla mistakenly handled "USING TTL 0" exactly like having no
USING TTL at all (i.e., it took the default TTL, instead of unlimited).
We had two xfailing tests demonstrating that Scylla's behavior in this
is different from Cassandra. Scylla's behavior in this case was also
undocumented.

By the way, Cassandra used to have the same bug (CASSANDRA-11207) but
it was fixed already in 2016 (Cassandra 3.6).

So in this patch we fix Scylla's "USING TTL 0" behavior to match the
documentation and Cassandra's behavior since 2016. One xfailing test
starts to pass and the second test passes this bug and fails on a
different one. This patch also adds a third test for "USING TTL ?"
with UNSET_VALUE - it behaves, on both Scylla and Cassandra, like a
missing "USING TTL".

The origin of this bug was that after parsing the statement, we saved
the USING TTL in an integer, and used 0 for the case of no USING TTL
given. This meant that we couldn't tell if we have USING TTL 0 or
no USING TTL at all. This patch uses an std::optional so we can tell
the case of a missing USING TTL from the case of USING TTL 0.

Fixes #6447

Signed-off-by: Nadav Har'El <nyh@scylladb.com>

Closes #13079
2023-03-08 16:18:23 +02:00
Avi Kivity
9454844751 cql3: modification_statement: unwrap unnecessary boolean_factors() call
for_each_expression() will recurse anyway.
2023-02-15 14:21:26 +02:00
Avi Kivity
1d0854c0bc cql3: modification_statement: use single expression for conditions
Currently, we use two vectors for static and regular column conditions,
each element referring to a single column. There's a comment that keeping
them separate makes things simpler, but in fact we always treat both
equally (except in one case where we look at just the regular columns
and check that no static column conditions exist).

Simplify by storing just a single expression, which can be a conjunction
of mulitple column conditions.

add_condition() is renamed to analyze_condition(), since it now longers
adds to the vectors.
2023-02-15 14:21:26 +02:00
Avi Kivity
5cb7655a9f cql3: modification_statment: fix lwt null equality rules mangling
search_and_replace() needs to return std::nullopt when it doesn't match,
or it doesn't recurse properly. Currently it doesn't break anything
because we only call the function on a binary_operator, but soon it will.
2023-02-15 14:21:26 +02:00
Avi Kivity
4d125bffdf cql3: grammar: communicate LWT IF conditions to AST as a simple expression
Instead of passing a vector of boolean factors, pass a single expression
(a conjunction).  This prepares the way for more complex expressions, but
no grammar changes are made here.

The expression is stored as optional, since we'll need a way to indicate
whether an IF clause was supplied or not. We could play games with
boolean_factors(), but it becomes too tricky.

The expressions are broken down back to boolean factors during prepare.
We'll later consolidate them too.
2023-02-15 14:21:26 +02:00
Avi Kivity
23bd7d24df cql3: column_condition: fold into modification_statement
Move column_condition_prepare() and its helper function into
modification_statement, its only caller. The column_condition.{cc,hh}
now become empty, so remove them.

This eliminates the column_condition concept, which was just a
custom expression, in favor of generic expressions. It still
has custom properties due to LWT specialness, but those custom
properties are isolated in column_condition_prepare().
2023-02-15 14:21:24 +02:00
Avi Kivity
12be5d4208 cql3: column_condition: inline column_condition_applies_to into its only caller
This two-liner can be trivilly inlined with no loss of meaning. Indeed
it's less confusing, because "applies_to" became less meaningful once
we integrated the column_value component into the expression.
2023-02-15 14:19:55 +02:00
Avi Kivity
82fb838a70 cql3: column_condition: inline column_condition_collect_marker_specification into its only caller
This one-liner can be trivilly inlined with no loss of meaning.
2023-02-15 14:19:55 +02:00
Avi Kivity
e7b9d9dab9 cql3: column_condition: eliminate column_condition class
It's become a wrapper around expression, so peel it off. The
methods are converted free functions, with the intent to later
inline them into their callers, as they are also mostly just
wrappers.
2023-02-15 14:19:55 +02:00
Avi Kivity
4d7d3c78a2 cql3: column_condition: eliminate column_condition::raw
It's now a thin wrapper around an expression, so peel the wrapper
and keep just the expression. A boolean expression is, after all,
a condition, and we'll make the condition statement-wide soon
rather than apply just to a column.
2023-02-15 14:19:55 +02:00
Avi Kivity
37c9c46101 cql3: column_condition: evaluate column_condition as a single expression
Instead of laboriously hand-evaluating each expression component,
construct one expression for the entire column_condition during
prepare time, and evaluate it using the generic machinery.

LWT IF evaluates equality against NULL considering two NULLs
as equal. We handle that by rewriting such expressions to use
null_handling_style::lwt_nulls.

Note we use expr::evaluate() rather than is_satisfied_by(), since
the latter doesn't like functions on the top-level, which we have
due to LIKE with constant pattern optimization. evaluate() is more
generic anyway.
2023-02-12 17:28:05 +02:00
Avi Kivity
b888e3d26a cql3: column_condition: convert _column to an expression
After this change, all components of column_condition are expressions.
One LWT-specific hack was removed from the evaluation path:

 - lists being represented as maps is made transparent by
   converting during evaluation with adjust_for_collections_as_maps()

column_condition::applies_to() previously handled a missing row
by materializing a NULL for the column being evaluated; now it
materializes a NULL row instead, since evaluation of the column is
moved to common code.

A few more cases in lwt_test became legal, though I'm not sure
exactly why in this patch.
2023-02-12 17:28:01 +02:00
Avi Kivity
3a2d8175fb cql3: update_parameters: use evaluation_inputs compatible row prefetch
update_parameters::prefetch_data is used for some list updates (which
need a read-before-write to determine the key to update) and for
LWT compare-and-swap. Currently they use a custom structure for
representing a read row.

Switch to the same structure that is used in evaluation_inputs (and
in SELECT statement evaluation) to the expression machinery can be reused.

The expression representation is irregular (with different fields for
the keys and regular/static columns), so we introduce an old_row
structure to hold both the clustering key and the regular row values
for cas_request.

A nice bonus is that we can use get_non_pk_values() to read the data
into the format expected by evaluation_inputs, but on the other hand
we have to adjust get_prefetched_list() to fix up the type of
the returned list (we return it as a map, not a list, so list updates
can access the index).
2023-02-12 17:25:41 +02:00
Avi Kivity
899c4a7f29 cql3: column_condition: make the left-hand-side part of column_condition::raw
LWT IF conditions are collected with the left-hand-side outside the
condition structure, then moved back to the prepared condition
structure during preparation. Change that so that the raw description
also contains the left-hand-side. This makes it more similar to expressions
(which LWT conditions aspire to be).

The change is mechanical; a bit of code that used to manage the std::pair
is moved to column_condition::raw::prepare instead. The schema is now also
passed since it's needed to prepare the left-hand-side.
2023-02-12 17:05:22 +02:00
Nadav Har'El
5bf94ae220 cql: allow disabling of USING TIMESTAMP sanity checking
As requested by issue #5619, commit 2150c0f7a2
added a sanity check for USING TIMESTAMP - the number specified in the
timestamp must not be more than 3 days into the future (when viewed as
a number of microseconds since the epoch).

This sanity checking helps avoid some annoying client-side bugs and
mis-configurations, but some users genuinely want to use arbitrary
or futuristic-looking timestamps and are hindered by this sanity check
(which Cassandra doesn't have, by the way).

So in this patch we add a new configuration option, restrict_future_timestamp
If set to "true", futuristic timestamps (more than 3 days into the future)
are forbidden. The "true" setting is the default (as has been the case
sinced #5619). Setting this option to "false" will allow using any 64-bit
integer as a timestamp, like is allowed Cassanda (and was allowed in
Scylla prior to #5619.

The error message in the case where a futuristic timestamp is rejected
now mentions the configuration paramter that can be used to disable this
check (this, and the option's name "restrict_*", is similar to other
so-called "safe mode" options).

This patch also includes a test, which works in Scylla and Cassandra,
with either setting of restrict_future_timestamp, checking the right
thing in all these cases (the futuristic timestamp can either be written
and read, or can't be written). I used this test to manually verify that
the new option works, defaults to "true", and when set to "false" Scylla
behaves like Cassandra.

Fixes #12527

Signed-off-by: Nadav Har'El <nyh@scylladb.com>

Closes #12537
2023-01-16 23:18:56 +02:00
Avi Kivity
654b96660a cql: modification_statement: drop protocol check for LWT
CQL protocol 1 did not support LWT, but since we don't support it
any more, we can drop the check and the supporting get_protocol_version()
helper.
2023-01-03 19:51:57 +02:00
Petr Gusev
b95305ae2b cql: refactor, inline modification_statement::validate_primary_key_restrictions
The function didn't add much value, just forwarded to _restrictions.
Removed it and called _restrictions->validate_primary_key directly.
2022-11-23 21:56:12 +04:00
Petr Gusev
c123f94110 cql: add column name to the error message in case of null primary key component
It's more user-friendly and the error message
corresponds to what Cassandra provides in this case.
2022-11-23 21:39:23 +04:00
Petr Gusev
7730c4718e cql: batch statement, inserting a row with a null key column should be forbidden
Regular INSERT statements with null values for primary key
components are rejected by Scylla since #9286 and #9314.
Batch statements missed a similar check, this patch
fixes it.

Fixes: #12060
2022-11-23 21:39:23 +04:00
Petr Gusev
89a5397d7c cql: wrong column name in error messages
If INSERT or DELETE statement is missing a non-last element of
the primary key, the error message generated contains
an invalid column name.

The problem occurs if the query contains a column with the list type,
otherwise
statement_restrictions::process_clustering_columns_restrictions
checks that all the components of the key are specified.

Fixes: #12046
2022-11-23 21:39:16 +04:00
Petr Gusev
0d443dfd16 modification_statement: fix LWT insert crash if clustering key is null
PR #9314 fixed a similar issue with regular insert statements
but missed the LWT code path.

It's expected behaviour of
modification_statement::create_clustering_ranges to return an
empty range in this case, since possible_lhs_values it
uses explicitly returns empty_value_set if it evaluates rhs
to null, and it has a comment about it (All NULL
comparisons fail; no column values match.) On the other hand,
all components of the primary key are required to be set,
this is checked at the prepare phase, in
modification_statement::process_where_clause. So the only
problem was modification_statement::execute_with_condition
was not expecting an empty clustering_range in case of
a null clustering key.

Fixes: #11954
2022-11-22 16:45:16 +04:00
Mikołaj Grzebieluch
82df8a9905 raft: broadcast_tables: add compilation of cql to intermediate language
We decided to extend `cql_statement` hierarchy with `strongly_consistent_modification_statement`
and `strongly_consistent_select_statement`. Statements operating on
system.broadcast_kv_store will be compiled to these new subclasses if
BROADCAST_TABLES flag is enabled.

If the query is executed on a shard other than 0 it's bounced to that shard.
2022-09-08 15:25:36 +02:00
Botond Dénes
d1d53f1b84 query: add tombstone-limit to read-command
Propagate the tombstone-limit from coordinator to replicas, to make sure
all is using the same limit.
2022-08-10 06:01:47 +03:00
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
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
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
1339ff1c79 cql3: Use expression instead of _partition_key_restrictions in the remaining code
There are still some places that use partition_key_restrictions
instead of _new_partition_key_restrictions in statement_restrictions.
Change them to use the new representation

Signed-off-by: Jan Ciolek <jan.ciolek@scylladb.com>
2022-07-01 16:29:10 +02:00
Jan Ciolek
de99c0a0fa cql3: Replace partition_key_restrictions->size()
Signed-off-by: Jan Ciolek <jan.ciolek@scylladb.com>
2022-07-01 16:29:10 +02:00
Jan Ciolek
e37ddd5b89 cql3: Remove single_column_restriction class
Now that all uses of this class have been
replaced by the generic restriction
the class is not used anywhere and can be removed.

Signed-off-by: Jan Ciolek <jan.ciolek@scylladb.com>
2022-07-01 15:53:19 +02:00
Piotr Dulikowski
e6beab3106 storage_proxy: add allow rate limit flag to mutate/mutate_result
Now, mutate/mutate_result accept a flag which decides whether the write
should be rate limited or not.

The new parameter is mandatory and all call sites were updated.
2022-06-22 20:16:49 +02:00
Avi Kivity
4f7cbbb54c cql3: column_condition: rename column member
Prefix with underscore as a data member.
2022-06-02 13:09:54 +03:00
cvybhu
51cdbdeacb cql3: Make parser output expression for relations
Parser used to output the where clause as a vector of relations,
but now we can change it to a vector of expressions.

Cql.g needs to be modified to output expressions instead
of relations.

The WHERE clause is kept in a few places in the code that
need to be changed to vector<expression>.

Finally relation->to_restriction is replaced by expr::to_restriction
and the expressions are converted to restrictions where required.

The relation class isn't used anywhere now and can be removed.

Signed-off-by: cvybhu <jan.ciolek@scylladb.com>
2022-05-16 18:17:58 +02:00
Avi Kivity
5937b1fa23 treewide: remove empty comments in top-of-files
After fcb8d040 ("treewide: use Software Package Data Exchange
(SPDX) license identifiers"), many dual-licensed files were
left with empty comments on top. Remove them to avoid visual
noise.

Closes #10562
2022-05-13 07:11:58 +02:00
Eliran Sinvani
bf50dbd35b cql3 statements: Change dependency test API to express better it's
purpose

Cql statements used to have two API functions, depends_on_keyspace and
depends_on_column_family. The former, took as a parameter only a table
name, which makes no sense. There could be multiple tables with the same
name each in a different keyspace and it doesn't make sense to
generalize the test - i.e to ask "Does a statement depend on any table
named XXX?"
In this change we unify the two calls to one - depends on that takes a
keyspace name and optionally also a table name, that way every logical
dependency tests that makes sense is supported by a single API call.
2022-02-27 11:48:03 +02:00
Piotr Dulikowski
2572104dfe modification_statement: propagate failed result through result_message::exception
Modifies the modification_statement code so that is converts failed
`result<>` into a `result_message::exception` without involving the C++
exception runtime.
2022-02-08 11:08:42 +01:00
Piotr Dulikowski
4c1eae7600 storage_proxy: change mutate_with_triggers to return future<result<>>
Changes the interface of `mutate_with_triggers` so that it returns
`future<result<>>` instead of `future<>`. No intermediate
`mutate_with_triggers_result` method is introduced because all call
sites will be changed in this PR so that they properly handle failed
`result<>`s with exceptions-as-values.
2022-02-08 11:08:42 +01:00