cql: add static row to CAS failure result if there are static conditions

Even if no rows match clustering key restrictions of a conditional
statement with static columns conditions, we still must include the
static column value into the CAS failure result set. For example,
the following conditional DELETE statement

  create table t(k int, c int, s int static, v int, primary key(k, c));
  insert into t(k, s) values(1, 1);
  delete v from t where k=1 and c=1 if v=1 and s=1;

must return

  [applied=False, v=null, s=1]

not just

  [applied=False, v=null, s=null]

To fix that, set partition_slice::option::always_return_static_content
for querying rows used for checking conditions so that we have the
static row in update_parameters::prefetch_data even if no regular row
matches clustering column restrictions. Plus modify cas_request::
applies_to() so that it sets is_in_cas_result_set flag for the static
row in case there are static column conditions, but the result set
happens to be empty.

As pointed out by Tomek, there's another reason to set partition_slice::
option::always_return_static_content apart from building a correct
result set on CAS failure. There could be a batch with two statements,
one with clustering key restrictions which select no row, and another
statement with only static column conditions. If we didn't enable this
flag, we wouldn't get a static row even if it exists, and static column
conditions would evaluate as if the static row didn't exist, for
example, the following batch

  create table t(k int, c int, s int static, primary key(k, c));
  insert into t(k, s) values(1, 1);
  begin batch
  insert into t(k, c) values(1, 1) if not exists
  update t set s = 2 where k = 1 if s = 1
  apply batch;

would fail although it clearly must succeed.
This commit is contained in:
Vladimir Davydov
2019-10-15 11:16:05 +03:00
parent e0b31dd273
commit 65b86d155e
3 changed files with 22 additions and 0 deletions

View File

@@ -121,10 +121,15 @@ bool cas_request::applies_to() const {
const partition_key& pkey = _key.front().start()->value().key().value();
const clustering_key empty_ckey = clustering_key::make_empty();
bool applies = true;
bool is_cas_result_set_empty = true;
bool has_static_column_conditions = false;
for (const cas_row_update& op: _updates) {
if (op.statement.has_conditions() == false) {
continue;
}
if (op.statement.has_static_column_conditions()) {
has_static_column_conditions = true;
}
// If a statement has only static columns conditions, we must ignore its clustering columns
// restriction when choosing a row to check the conditions, i.e. choose any partition row,
// because any of them must have static columns and that's all we need to know if the
@@ -142,6 +147,7 @@ bool cas_request::applies_to() const {
const auto* row = _rows->find_row(pkey, ckey);
if (row) {
row->is_in_cas_result_set = true;
is_cas_result_set_empty = false;
}
if (!applies) {
// No need to check this condition as we have already failed a previous one.
@@ -151,6 +157,19 @@ bool cas_request::applies_to() const {
}
applies = op.statement.applies_to(row, op.options);
}
if (has_static_column_conditions && is_cas_result_set_empty) {
// If none of the fetched rows matches clustering key restrictions and hence none of them is
// included into the CAS result set, but there is a static column condition in the CAS batch,
// we must still include the static row into the result set. Consider the following example:
// CREATE TABLE t(p int, c int, s int static, v int, PRIMARY KEY(p, c));
// INSERT INTO t(p, s) VALUES(1, 1);
// DELETE v FROM t WHERE p=1 AND c=1 IF v=1 AND s=1;
// In this case the conditional DELETE must return [applied=False, v=null, s=1].
const auto* row = _rows->find_row(pkey, empty_ckey);
if (row) {
row->is_in_cas_result_set = true;
}
}
return applies;
}

View File

@@ -263,6 +263,8 @@ private:
public:
// True if the statement has IF conditions. Pre-computed during prepare.
bool has_conditions() const { return _has_regular_column_conditions || _has_static_column_conditions; }
// True if the statement has IF conditions that apply to static columns.
bool has_static_column_conditions() const { return _has_static_column_conditions; }
// True if this statement needs to read only static column values to check if it can be applied.
bool has_only_static_column_conditions() const { return !_has_regular_column_conditions && _has_static_column_conditions; }

View File

@@ -60,6 +60,7 @@ public:
static constexpr query::partition_slice::option_set options = query::partition_slice::option_set::of<
query::partition_slice::option::send_partition_key,
query::partition_slice::option::send_clustering_key,
query::partition_slice::option::always_return_static_content,
query::partition_slice::option::collections_as_maps>();
// Holder for data for