Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge 'cql: add missing functions for the COUNTER column type' from N…
…adav Har'El We have had support for COUNTER columns for quite some time now, but some functionality was left unimplemented - various internal and CQL functions resulted in "unimplemented" messages when used, and the goal of this series is to fix those issues. The primary goal was to add the missing support for CASTing counters to other types in CQL (issue #14501), but we also add the missing CQL `counterasblob()` and `blobascounter()` functions (issue #14742). As usual, the series includes extensive functional tests for these features, and one pre-existing test for CAST that used to fail now begins to pass. Fixes #14501 Fixes #14742 Closes #14745 * github.com:scylladb/scylladb: test/cql-pytest: test confirming that casting to counter doesn't work cql: support casting of counter to other types cql: implement missing counterasblob() and blobascounter() functions cql: implement missing type functions for "counters" type
- Loading branch information
Showing
7 changed files
with
240 additions
and
19 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
# Copyright 2023-present ScyllaDB | ||
# | ||
# SPDX-License-Identifier: AGPL-3.0-or-later | ||
|
||
############################################################################### | ||
# Tests for various operations on COUNTER columns. | ||
# See also tests for casting involving counter columns in test_cast_data.py | ||
############################################################################### | ||
|
||
import pytest | ||
from util import new_test_table, unique_key_int | ||
from cassandra.protocol import InvalidRequest | ||
|
||
@pytest.fixture(scope="module") | ||
def table1(cql, test_keyspace): | ||
with new_test_table(cql, test_keyspace, "p int PRIMARY KEY, i bigint, v int") as table: | ||
yield table | ||
|
||
@pytest.fixture(scope="module") | ||
def table2(cql, test_keyspace): | ||
with new_test_table(cql, test_keyspace, "p int PRIMARY KEY, c counter") as table: | ||
yield table | ||
|
||
# Test that the function counterasblob() exists and works as expected - | ||
# same as bigintasblob on the same number (a counter is a 64-bit number). | ||
# Reproduces #14742 | ||
def test_counter_to_blob(cql, table1, table2): | ||
p = unique_key_int() | ||
cql.execute(f'UPDATE {table1} SET i = 1000 WHERE p = {p}') | ||
cql.execute(f'UPDATE {table2} SET c = c + 1000 WHERE p = {p}') | ||
expected = b'\x00\x00\x00\x00\x00\x00\x03\xe8' | ||
assert [(expected,)] == list(cql.execute(f"SELECT bigintasblob(i) FROM {table1} WHERE p={p}")) | ||
assert [(expected,)] == list(cql.execute(f"SELECT counterasblob(c) FROM {table2} WHERE p={p}")) | ||
# Although the representation of the counter and bigint types are the | ||
# same (64-bit), you can't use the wrong "*asblob()" function: | ||
with pytest.raises(InvalidRequest, match='counterasblob'): | ||
cql.execute(f"SELECT counterasblob(i) FROM {table1} WHERE p={p}") | ||
# The opposite order is allowed in Scylla because of #14319, so let's | ||
# split it into a second test test_counter_to_blob2: | ||
@pytest.mark.xfail(reason="issue #14319") | ||
def test_counter_to_blob2(cql, table1, table2): | ||
p = unique_key_int() | ||
cql.execute(f'UPDATE {table2} SET c = c + 1000 WHERE p = {p}') | ||
# Reproduces #14319: | ||
with pytest.raises(InvalidRequest, match='bigintasblob'): | ||
cql.execute(f"SELECT bigintasblob(c) FROM {table2} WHERE p={p}") | ||
|
||
# Test that the function blobascounter() exists and works as expected. | ||
# Reproduces #14742 | ||
def test_counter_from_blob(cql, table1): | ||
p = unique_key_int() | ||
cql.execute(f'UPDATE {table1} SET i = 1000 WHERE p = {p}') | ||
assert [(1000,)] == list(cql.execute(f"SELECT blobascounter(bigintasblob(i)) FROM {table1} WHERE p={p}")) | ||
|
||
# blobascounter() must insist to receive a properly-sized (8-byte) blob. | ||
# If it accepts a shorter blob (e.g., 4 bytes) and returns that to the driver, | ||
# it will confuse the driver (the driver will expect to read 8 bytes for the | ||
# bigint but will get only 4). | ||
# We have test_native_functions.py::test_blobas_wrong_size() that verifies | ||
# that this protection works for the bigint type, but it turns out it also | ||
# needs to be separately enforced for the counter type. | ||
def test_blobascounter_wrong_size(cql, table1): | ||
p = unique_key_int() | ||
cql.execute(f'UPDATE {table1} SET v = 1000 WHERE p = {p}') | ||
with pytest.raises(InvalidRequest, match='blobascounter'): | ||
cql.execute(f"SELECT blobascounter(intasblob(v)) FROM {table1} WHERE p={p}") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
# Copyright 2023-present ScyllaDB | ||
# | ||
# SPDX-License-Identifier: AGPL-3.0-or-later | ||
|
||
############################################################################### | ||
# Tests for various native (built-in) scalar functions that can be used in | ||
# various SELECT, INSERT or UPDATE requests. Note we also have tests for | ||
# some of these functions in many other test files. For example, the tests | ||
# for the cast() function are in test_cast_data.py. | ||
############################################################################### | ||
|
||
import pytest | ||
from util import new_test_table, unique_key_int | ||
from cassandra.protocol import InvalidRequest | ||
|
||
@pytest.fixture(scope="module") | ||
def table1(cql, test_keyspace): | ||
with new_test_table(cql, test_keyspace, "p int, i int, g bigint, b blob, s text, t timestamp, u timeuuid, PRIMARY KEY (p)") as table: | ||
yield table | ||
|
||
# Check that a function that can take a column name as a parameter, can also | ||
# take a constant. This feature is barely useful for WHERE clauses, and | ||
# even less useful for selectors, but should be allowed for both. | ||
# Reproduces #12607. | ||
@pytest.mark.xfail(reason="issue #12607") | ||
def test_constant_function_parameter(cql, table1): | ||
p = unique_key_int() | ||
cql.execute(f"INSERT INTO {table1} (p, b) VALUES ({p}, 0x03)") | ||
assert [(p,)] == list(cql.execute(f"SELECT p FROM {table1} WHERE p={p} AND b=tinyintAsBlob(3) ALLOW FILTERING")) | ||
assert [(b'\x04',)] == list(cql.execute(f"SELECT tinyintAsBlob(4) FROM {table1} WHERE p={p}")) | ||
|
||
# According to the documentation, "The `minTimeuuid` function takes a | ||
# `timestamp` value t, either a timestamp or a date string.". But although | ||
# both cases are supported with constant parameters in WHERE restrictions, | ||
# in a *selector* (the first part of the SELECT, saying what to select), it | ||
# turns out that ONLY a timestamp column is allowed. Although this is | ||
# undocumented behavior, both Cassandra and Scylla share it so we deem it | ||
# correct. | ||
def test_selector_mintimeuuid(cql, table1): | ||
p = unique_key_int() | ||
cql.execute(f"INSERT INTO {table1} (p, s, t, i) VALUES ({p}, '2013-02-02 10:00+0000', 123, 456)") | ||
# We just check this works, not what the value is: | ||
cql.execute(f"SELECT mintimeuuid(t) FROM {table1} WHERE p={p}") | ||
# This doesn't work - despite the documentation, in a selector a | ||
# date string is not supported by mintimeuuid. | ||
with pytest.raises(InvalidRequest, match='of type timestamp'): | ||
cql.execute(f"SELECT mintimeuuid(s) FROM {table1} WHERE p={p}") | ||
# Other integer types also don't work, it must be a timestamp: | ||
with pytest.raises(InvalidRequest, match='of type timestamp'): | ||
cql.execute(f"SELECT mintimeuuid(i) FROM {table1} WHERE p={p}") | ||
|
||
# Cassandra allows the implicit (and wrong!) casting of a bigint returned | ||
# by writetime() to the timestamp type required by mintimeuuid(). Scylla | ||
# doesn't. I'm not sure which behavior we should consider correct, but it's | ||
# useful to have a test that demonstrates this incompatibility. | ||
# Reproduces #14319. | ||
@pytest.mark.xfail(reason="issue #14319") | ||
def test_selector_mintimeuuid_64bit(cql, table1): | ||
p = unique_key_int() | ||
cql.execute(f"INSERT INTO {table1} (p, g) VALUES ({p}, 123)") | ||
cql.execute(f"SELECT mintimeuuid(g) FROM {table1} WHERE p={p}") | ||
cql.execute(f"SELECT mintimeuuid(writetime(g)) FROM {table1} WHERE p={p}") | ||
|
||
# blobasbigint() must insist to receive a properly-sized (8-byte) blob. | ||
# If it accepts a shorter blob (e.g., 4 bytes) and returns that to the driver, | ||
# it will confuse the driver (the driver will expect to read 8 bytes for the | ||
# bigint but will get only 4). | ||
def test_blobas_wrong_size(cql, table1): | ||
p = unique_key_int() | ||
cql.execute(f"INSERT INTO {table1} (p, i) VALUES ({p}, 123)") | ||
# Cassandra and Scylla print: "In call to function system.blobasbigint, | ||
# value 0x0000007b is not a valid binary representation for type bigint". | ||
with pytest.raises(InvalidRequest, match='blobasbigint'): | ||
cql.execute(f"SELECT blobasbigint(intasblob(i)) FROM {table1} WHERE p={p}") |
Oops, something went wrong.