statements/cas_request: fix crash on empty clustering range in LWT

LWT queries with empty clustering range used to cause a crash.
For example in:
```cql
UPDATE tab SET r = 9000 WHERE p = 1  AND c = 2 AND c = 2000 IF r = 3
```
The range of `c` is empty - there are no valid values.

This caused a segfault when accessing the `first` range:
```c++
op.ranges.front()
```

To fix it let's throw en exception when the clustering range
is empty. Cassandra also rejects queries with `c = 1 AND c = 2`.

There's also a check for empty partition range, as it used
to crash in the past, can't really hurt to add it.

Signed-off-by: Jan Ciolek <jan.ciolek@scylladb.com>
This commit is contained in:
Jan Ciolek
2023-06-28 09:11:02 +02:00
parent 8d1dfbf0d9
commit ccdb26bf9e
2 changed files with 6 additions and 1 deletions

View File

@@ -123,6 +123,9 @@ std::optional<mutation> cas_request::apply(foreign_ptr<lw_shared_ptr<query::resu
cas_request::old_row cas_request::find_old_row(const cas_row_update& op) const {
static const clustering_key empty_ckey = clustering_key::make_empty();
if (_key.empty()) {
throw exceptions::invalid_request_exception("Empty partition key range");
}
const partition_key& pkey = _key.front().start()->value().key().value();
// We must ignore statement clustering column restriction when
// choosing a row to check the conditions. If there is no
@@ -134,6 +137,9 @@ cas_request::old_row cas_request::find_old_row(const cas_row_update& op) const {
// CREATE TABLE t(p int, c int, s int static, v int, PRIMARY KEY(p, c));
// INSERT INTO t(p, s) VALUES(1, 1);
// UPDATE t SET v=1 WHERE p=1 AND c=1 IF s=1;
if (op.ranges.empty()) {
throw exceptions::invalid_request_exception("Empty clustering range");
}
const clustering_key& ckey = op.ranges.front().start() ? op.ranges.front().start()->value() : empty_ckey;
auto row = _rows.find_row(pkey, ckey);
auto ckey_ptr = &ckey;

View File

@@ -73,7 +73,6 @@ def test_lwt_empty_partition_range(cql, table1):
# Generate an LWT update where there is no value for the clustering key,
# as the WHERE restricts it using `c = 2 AND c = 3`.
# Such queries are rejected.
@pytest.mark.skip(reason="crashes scylla, see issue #13129")
def test_lwt_empty_clustering_range(cql, table1):
with pytest.raises(InvalidRequest):
cql.execute(f"UPDATE {table1} SET r = 9000 WHERE p = 1 AND c = 2 AND c = 2000 IF r = 3")