# Copyright 2024-present ScyllaDB # # SPDX-License-Identifier: LicenseRef-ScyllaDB-Source-Available-1.0 ############################################################################# # Tests for SELECT of a specific key in a collection column ############################################################################# import pytest from cassandra.protocol import InvalidRequest from .util import unique_name, unique_key_int, new_test_table, new_type, new_function @pytest.fixture(scope="module") def table1(cql, test_keyspace): table = test_keyspace + "." + unique_name() cql.execute(f"CREATE TABLE {table} (p int PRIMARY KEY, m map)") yield table cql.execute("DROP TABLE " + table) def test_basic_int_key_selection(cql, table1): p = unique_key_int() cql.execute(f"INSERT INTO {table1}(p,m) VALUES ({p}, " + "{1:10,2:20})") assert list(cql.execute(f"SELECT m[1] FROM {table1} WHERE p={p}")) == [(10,)] assert list(cql.execute(f"SELECT m[2] FROM {table1} WHERE p={p}")) == [(20,)] assert list(cql.execute(f"SELECT m[3] FROM {table1} WHERE p={p}")) == [(None,)] def test_basic_string_key_selection(cql, test_keyspace): schema = 'p int PRIMARY KEY, m map' with new_test_table(cql, test_keyspace, schema) as table: p = unique_key_int() cql.execute(f"INSERT INTO {table}(p,m) VALUES ({p}, " + "{'aa':10,'ab':20})") assert list(cql.execute(f"SELECT m['aa'] FROM {table} WHERE p={p}")) == [(10,)] assert list(cql.execute(f"SELECT m['ab'] FROM {table} WHERE p={p}")) == [(20,)] assert list(cql.execute(f"SELECT m['ac'] FROM {table} WHERE p={p}")) == [(None,)] def test_subscript_type_mismatch(cql, table1): p = unique_key_int() cql.execute(f"INSERT INTO {table1}(p,m) VALUES ({p}, " + "{1:10,2:20})") with pytest.raises(InvalidRequest): cql.execute(f"SELECT m['x'] FROM {table1} WHERE p={p}") def test_subscript_with_alias(cql, table1): p = unique_key_int() cql.execute(f"INSERT INTO {table1}(p,m) VALUES ({p}, " + "{1:10,2:20})") assert [(r.m1, r.m2) for r in cql.execute(f"SELECT m[1] as m1, m[2] as m2 FROM {table1} WHERE p={p}")] == [(10, 20)] def test_frozen_map_subscript(cql, test_keyspace): schema = 'p int PRIMARY KEY, m frozen>' with new_test_table(cql, test_keyspace, schema) as table: p = unique_key_int() cql.execute(f"INSERT INTO {table}(p,m) VALUES ({p}, " + "{1:10,2:20})") assert list(cql.execute(f"SELECT m[1] FROM {table} WHERE p={p}")) == [(10,)] assert list(cql.execute(f"SELECT m[2] FROM {table} WHERE p={p}")) == [(20,)] assert list(cql.execute(f"SELECT m[3] FROM {table} WHERE p={p}")) == [(None,)] def test_nested_key_selection(cql, test_keyspace): schema = 'p int PRIMARY KEY, m map>>' with new_test_table(cql, test_keyspace, schema) as table: p = unique_key_int() cql.execute(f"INSERT INTO {table}(p, m) VALUES ({p}, " + "{'1': {'a': 10, 'b': 11}, '2': {'a': 12}})") assert list(cql.execute(f"SELECT m['1']['a'] FROM {table} WHERE p={p}")) == [(10,)] assert list(cql.execute(f"SELECT m['1']['b'] FROM {table} WHERE p={p}")) == [(11,)] assert list(cql.execute(f"SELECT m['2']['a'] FROM {table} WHERE p={p}")) == [(12,)] assert list(cql.execute(f"SELECT m['2']['b'] FROM {table} WHERE p={p}")) == [(None,)] def test_prepare_key(cql, table1): p = unique_key_int() cql.execute(f"INSERT INTO {table1} (p,m) VALUES ({p}, " + "{1:10,2:20})") lookup1 = cql.prepare(f"SELECT m[?] FROM {table1} WHERE p = ?") assert list(cql.execute(lookup1, [1, p])) == [(10,)] assert list(cql.execute(lookup1, [2, p])) == [(20,)] assert list(cql.execute(lookup1, [3, p])) == [(None,)] lookup2 = cql.prepare(f"SELECT m[:x1], m[:x2] FROM {table1} WHERE p = :key") assert list(cql.execute(lookup2, {'x1':2, 'x2':1, 'key':p})) == [(20,10)] def test_null_map(cql, table1): p = unique_key_int() cql.execute(f"INSERT INTO {table1}(p) VALUES ({p})") assert list(cql.execute(f"SELECT m[1] FROM {table1} WHERE p={p}")) == [(None,)] # scylla only because scylla returns null while cassandra returns error def test_null_subscript(scylla_only, cql, table1): p = unique_key_int() cql.execute(f"INSERT INTO {table1}(p,m) VALUES ({p}, " + "{1:10,2:20})") assert list(cql.execute(f"SELECT m[null] FROM {table1} WHERE p={p}")) == [(None,)] def test_subscript_and_field(cql, test_keyspace): with new_type(cql, test_keyspace, '(a int)') as typ: schema = f"p int PRIMARY KEY, m map>" with new_test_table(cql, test_keyspace, schema) as table: p = unique_key_int() cql.execute(f"INSERT INTO {table}(p,m) VALUES ({p}, " + "{1:{a:10}})") assert list(cql.execute(f"SELECT m[1].a FROM {table} WHERE p={p}")) == [(10,)] def test_field_and_subscript(cql, test_keyspace): with new_type(cql, test_keyspace, '(a frozen>)') as typ: schema = f"p int PRIMARY KEY, t {typ}" with new_test_table(cql, test_keyspace, schema) as table: p = unique_key_int() cql.execute(f"INSERT INTO {table}(p,t) VALUES ({p}, " + "{a:{1:10}})") assert list(cql.execute(f"SELECT t.a[1] FROM {table} WHERE p={p}")) == [(10,)] def test_field_and_subscript_and_field(cql, test_keyspace): with new_type(cql, test_keyspace, '(b int)') as typ1, \ new_type(cql, test_keyspace, f"(a frozen>)") as typ2: schema = f"p int PRIMARY KEY, t {typ2}" with new_test_table(cql, test_keyspace, schema) as table: p = unique_key_int() cql.execute(f"INSERT INTO {table}(p,t) VALUES ({p}, " + "{a:{1:{b:10}}})") assert list(cql.execute(f"SELECT t.a[1].b FROM {table} WHERE p={p}")) == [(10,)] def test_other_types_cannot_be_subscripted(cql, table1): with pytest.raises(InvalidRequest, match='not a'): cql.execute(f"SELECT p[2] FROM {table1}") with pytest.raises(InvalidRequest, match='not a'): cql.execute(f"SELECT token(p)[2] FROM {table1}") def test_udf_subscript(scylla_only, cql, test_keyspace, table1): fn = "(k int) CALLED ON NULL INPUT RETURNS int LANGUAGE Lua AS 'return k+1'" with new_function(cql, test_keyspace, fn, 'add_one'): p = unique_key_int() cql.execute(f"INSERT INTO {table1}(p,m) VALUES ({p}, " + "{1:10,2:20})") assert list(cql.execute(f"SELECT m[add_one(1)] FROM {table1} WHERE p={p}")) == [(20,)] # cassandra doesn't support subscript on a list def test_list_subscript(scylla_only, cql, test_keyspace): schema = 'p int PRIMARY KEY, l list' with new_test_table(cql, test_keyspace, schema) as table: p = unique_key_int() cql.execute(f"INSERT INTO {table}(p,l) VALUES ({p}, " + "[10,20])") assert list(cql.execute(f"SELECT l[0] FROM {table} WHERE p={p}")) == [(10,)] assert list(cql.execute(f"SELECT l[1] FROM {table} WHERE p={p}")) == [(20,)] assert list(cql.execute(f"SELECT l[2] FROM {table} WHERE p={p}")) == [(None,)] assert list(cql.execute(f"SELECT l[10] FROM {table} WHERE p={p}")) == [(None,)] def test_set_subscript(cql, test_keyspace): schema = 'p int PRIMARY KEY, s set' with new_test_table(cql, test_keyspace, schema) as table: p = unique_key_int() cql.execute(f"INSERT INTO {table}(p,s) VALUES ({p}, " + "{10,20})") assert list(cql.execute(f"SELECT s[0] FROM {table} WHERE p={p}")) == [(None,)] assert list(cql.execute(f"SELECT s[10] FROM {table} WHERE p={p}")) == [(10,)] assert list(cql.execute(f"SELECT s[11] FROM {table} WHERE p={p}")) == [(None,)] assert list(cql.execute(f"SELECT s[20] FROM {table} WHERE p={p}")) == [(20,)] # scylla only because cassandra doesn't support lua language @pytest.mark.xfail(reason="#22075") def test_subscript_function_arg(scylla_only, cql, test_keyspace, table1): fn = "(k int) CALLED ON NULL INPUT RETURNS int LANGUAGE Lua AS 'return k+1'" with new_function(cql, test_keyspace, fn, 'add_one'): p = unique_key_int() cql.execute(f"INSERT INTO {table1}(p,m) VALUES ({p}, " + "{1:10,2:20})") assert list(cql.execute(f"SELECT add_one(m[1]) FROM {table1} WHERE p={p}")) == [(11,)]