Files
scylla/test/cql-pytest/cassandra_tests/validation/operations/alter_test.py
Alexander Turetskiy f30b5473ab cql: Reject empty options while altering a keyspace
Reject ALTER KEYSPACE request for NetworkTopologyStrategy when
replication options are missed.

Also reject CREATE KEYSPACE with no replication factor options.
Cassandra has a default_keyspace_rf configuration that may allow such
CREATE KEYSPACE commands, but Scylla doesn't have this option (refs #16028).

fixes #10036

Closes scylladb/scylladb#16221
2023-12-10 17:44:35 +02:00

351 lines
23 KiB
Python

# This file was translated from the original Java test from the Apache
# Cassandra source repository, as of commit 6ca34f81386dc8f6020cdf2ea4246bca2a0896c5
#
# The original Apache Cassandra license:
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from cassandra_tests.porting import *
def testDropColumnAsPreparedStatement(cql, test_keyspace):
with create_table(cql, test_keyspace, "(key int PRIMARY KEY, value int)") as table:
prepared = cql.prepare(f"ALTER TABLE {table} DROP value")
cql.execute(f"INSERT INTO {table} (key, value) VALUES (1, 1)")
assert_rows(cql.execute(f"SELECT * FROM {table}"), [1, 1])
cql.execute(prepared)
cql.execute(f"ALTER TABLE {table} ADD value int")
assert_rows(cql.execute(f"SELECT * FROM {table}"), [1, None])
def testAddList(cql, test_keyspace):
with create_table(cql, test_keyspace, "(id text PRIMARY KEY, content text)") as table:
execute(cql, table, "ALTER TABLE %s ADD myCollection list<text>")
execute(cql, table, "INSERT INTO %s (id, content, myCollection) VALUES ('test', 'first test', ['first element'])")
assert_rows(execute(cql, table, "SELECT * FROM %s"), ["test", "first test", ["first element"]])
def testDropList(cql, test_keyspace):
with create_table(cql, test_keyspace, "(id text PRIMARY KEY, content text, myCollection list<text>)") as table:
execute(cql, table, "INSERT INTO %s (id, content , myCollection) VALUES ('test', 'first test', ['first element']);")
execute(cql, table, "ALTER TABLE %s DROP myCollection")
assert_rows(execute(cql, table, "SELECT * FROM %s;"), ["test", "first test"])
def testAddMap(cql, test_keyspace):
with create_table(cql, test_keyspace, "(id text PRIMARY KEY, content text)") as table:
execute(cql, table, "ALTER TABLE %s ADD myCollection map<text, text>;")
execute(cql, table, "INSERT INTO %s (id, content , myCollection) VALUES ('test', 'first test', { '1' : 'first element'});")
assert_rows(execute(cql, table, "SELECT * FROM %s;"), ["test", "first test", {"1": "first element"}])
def testDropMap(cql, test_keyspace):
with create_table(cql, test_keyspace, "(id text PRIMARY KEY, content text, myCollection map<text, text>)") as table:
execute(cql, table, "INSERT INTO %s (id, content , myCollection) VALUES ('test', 'first test', { '1' : 'first element'})")
execute(cql, table, "ALTER TABLE %s DROP myCollection")
assert_rows(execute(cql, table, "SELECT * FROM %s;"), ["test", "first test"])
def testDropListAndAddListWithSameName(cql, test_keyspace):
with create_table(cql, test_keyspace, "(id text PRIMARY KEY, content text, myCollection list<text>)") as table:
execute(cql, table, "INSERT INTO %s (id, content, myCollection) VALUES ('test', 'first test', ['first element'])")
execute(cql, table, "ALTER TABLE %s DROP myCollection")
execute(cql, table, "ALTER TABLE %s ADD myCollection list<text>")
assert_rows(execute(cql, table, "SELECT * FROM %s;"), ["test", "first test", None])
execute(cql, table, "UPDATE %s set myCollection = ['second element'] WHERE id = 'test'")
assert_rows(execute(cql, table, "SELECT * FROM %s;"), ["test", "first test", ["second element"]])
def testDropListAndAddMapWithSameName(cql, test_keyspace):
with create_table(cql, test_keyspace, "(id text PRIMARY KEY, content text, myCollection list<text>)") as table:
execute(cql, table, "INSERT INTO %s (id, content, myCollection) VALUES ('test', 'first test', ['first element'])")
execute(cql, table, "ALTER TABLE %s DROP myCollection")
assert_invalid(cql, table, "ALTER TABLE %s ADD myCollection map<int, int>")
@pytest.mark.xfail(reason="Issue #9929")
def testDropWithTimestamp(cql, test_keyspace):
with create_table(cql, test_keyspace, "(id int, c1 int, v1 int, todrop int, PRIMARY KEY (id, c1))") as table:
for i in range(5):
execute(cql, table, "INSERT INTO %s (id, c1, v1, todrop) VALUES (?, ?, ?, ?) USING TIMESTAMP ?", 1, i, i, i, 10000 * i)
# flush is necessary since otherwise the values of `todrop` will get discarded during
# alter statement
flush(cql, table)
execute(cql, table, "ALTER TABLE %s DROP todrop USING TIMESTAMP 20000")
execute(cql, table, "ALTER TABLE %s ADD todrop int")
execute(cql, table, "INSERT INTO %s (id, c1, v1, todrop) VALUES (?, ?, ?, ?) USING TIMESTAMP ?", 1, 100, 100, 100, 30000)
assert_rows(execute(cql, table, "SELECT id, c1, v1, todrop FROM %s"),
[1, 0, 0, None],
[1, 1, 1, None],
[1, 2, 2, None],
[1, 3, 3, 3],
[1, 4, 4, 4],
[1, 100, 100, 100])
@pytest.mark.xfail(reason="Issue #9930")
def testDropAddWithDifferentKind(cql, test_keyspace):
with create_table(cql, test_keyspace, "(a int, b int, c int, d int static, PRIMARY KEY (a, b))") as table:
execute(cql, table, "ALTER TABLE %s DROP c")
execute(cql, table, "ALTER TABLE %s DROP d")
assert_invalid_message(cql, table, "Cannot re-add previously dropped column 'c' of kind STATIC, incompatible with previous kind REGULAR",
"ALTER TABLE %s ADD c int static")
assert_invalid_message(cql, table, "Cannot re-add previously dropped column 'd' of kind REGULAR, incompatible with previous kind STATIC",
"ALTER TABLE %s ADD d int")
@pytest.mark.xfail(reason="Issue #9929")
def testDropStaticWithTimestamp(cql, test_keyspace):
with create_table(cql, test_keyspace, "(id int, c1 int, v1 int, todrop int static, PRIMARY KEY (id, c1))") as table:
for i in range(5):
execute(cql, table, "INSERT INTO %s (id, c1, v1, todrop) VALUES (?, ?, ?, ?) USING TIMESTAMP ?", 1, i, i, i, 10000 * i)
# flush is necessary since otherwise the values of `todrop` will get discarded during
# alter statement
flush(cql, table)
execute(cql, table, "ALTER TABLE %s DROP todrop USING TIMESTAMP 20000")
execute(cql, table, "ALTER TABLE %s ADD todrop int static")
execute(cql, table, "INSERT INTO %s (id, c1, v1, todrop) VALUES (?, ?, ?, ?) USING TIMESTAMP ?", 1, 100, 100, 100, 30000)
# static column value with largest timestamp will be available again
assert_rows(execute(cql, table, "SELECT id, c1, v1, todrop FROM %s"),
[1, 0, 0, 4],
[1, 1, 1, 4],
[1, 2, 2, 4],
[1, 3, 3, 4],
[1, 4, 4, 4],
[1, 100, 100, 4])
@pytest.mark.xfail(reason="Issue #9929")
def testDropMultipleWithTimestamp(cql, test_keyspace):
with create_table(cql, test_keyspace, "(id int, c1 int, v1 int, todrop1 int, todrop2 int, PRIMARY KEY (id, c1))") as table:
for i in range(5):
execute(cql, table, "INSERT INTO %s (id, c1, v1, todrop1, todrop2) VALUES (?, ?, ?, ?, ?) USING TIMESTAMP ?", 1, i, i, i, i, 10000 * i)
# flush is necessary since otherwise the values of `todrop1` and `todrop2` will get discarded during
# alter statement
flush(cql, table)
execute(cql, table, "ALTER TABLE %s DROP (todrop1, todrop2) USING TIMESTAMP 20000;")
execute(cql, table, "ALTER TABLE %s ADD todrop1 int;")
execute(cql, table, "ALTER TABLE %s ADD todrop2 int;")
execute(cql, table, "INSERT INTO %s (id, c1, v1, todrop1, todrop2) VALUES (?, ?, ?, ?, ?) USING TIMESTAMP ?", 1, 100, 100, 100, 100, 40000)
assert_rows(execute(cql, table, "SELECT id, c1, v1, todrop1, todrop2 FROM %s"),
[1, 0, 0, None, None],
[1, 1, 1, None, None],
[1, 2, 2, None, None],
[1, 3, 3, 3, 3],
[1, 4, 4, 4, 4],
[1, 100, 100, 100, 100])
def testChangeStrategyWithUnquotedAgrument(cql, test_keyspace):
with create_table(cql, test_keyspace, "(id text PRIMARY KEY)") as table:
assert_invalid_syntax(cql, table,
"ALTER TABLE %s WITH caching = {'keys' : 'all', 'rows_per_partition' : ALL};")
# tests CASSANDRA-7976
def testAlterIndexInterval(cql, test_keyspace):
with create_table(cql, test_keyspace, "(id uuid, album text, atrist text, data blob, PRIMARY KEY (id))") as table:
execute(cql, table, "ALTER TABLE %s WITH min_index_interval=256 AND max_index_interval=512")
[ks, cf] = table.split('.')
options = cql.cluster.metadata.keyspaces[ks].tables[cf].options
assert options['min_index_interval'] == 256
assert options['max_index_interval'] == 512
execute(cql, table, "ALTER TABLE %s WITH caching = {}")
options = cql.cluster.metadata.keyspaces[ks].tables[cf].options
assert options['min_index_interval'] == 256
assert options['max_index_interval'] == 512
# Migrated from cql_tests.py:TestCQL.create_alter_options_test()
@pytest.mark.xfail(reason="Issue #9929, #9935")
def testCreateAlterKeyspaces(cql, test_keyspace, this_dc):
assert_invalid_throw(cql, test_keyspace, SyntaxException, "CREATE KEYSPACE ks1")
assert_invalid_throw(cql, test_keyspace, ConfigurationException, "CREATE KEYSPACE ks1 WITH replication= { 'replication_factor' : 1 }")
with create_keyspace(cql, "replication={ 'class' : 'SimpleStrategy', 'replication_factor' : 1 }") as ks1:
with create_keyspace(cql, "replication={ 'class' : 'SimpleStrategy', 'replication_factor' : 1 } AND durable_writes=false") as ks2:
assert_rows_ignoring_order_and_extra(execute(cql, ks1, "SELECT keyspace_name, durable_writes FROM system_schema.keyspaces"),
[ks1, True],
[ks2, False])
execute(cql, ks1, "ALTER KEYSPACE %s WITH replication = { 'class' : 'NetworkTopologyStrategy', '" + this_dc + "' : 1 } AND durable_writes=False")
execute(cql, ks2, "ALTER KEYSPACE %s WITH durable_writes=true")
assert_rows_ignoring_order_and_extra(execute(cql, ks1, "SELECT keyspace_name, durable_writes, replication FROM system_schema.keyspaces"),
[ks1, False, {"class": "org.apache.cassandra.locator.NetworkTopologyStrategy", this_dc: "1"}],
[ks2, True, {"class": "org.apache.cassandra.locator.SimpleStrategy", "replication_factor": "1"}])
assert_invalid_throw(cql, ks1, ConfigurationException, "CREATE TABLE %s.cf1 (a int PRIMARY KEY, b int) WITH compaction = { 'min_threshold' : 4 }")
with create_table(cql, ks1, "(a int PRIMARY KEY, b int) WITH compaction = { 'class' : 'SizeTieredCompactionStrategy', 'min_threshold' : 7 }") as table:
[ks, cf] = table.split('.')
# There's a minor difference here between Scylla and Cassandra-
# Cassandra expands the name SizeTieredCompactionStrategy to
# org.apache.cassandra.db.compaction.SizeTieredCompactionStrategy,
# and stores that in system_schema.tables. Scylla doesn't -
# it stores the original short name given in the table creation
# command. See issue #9935.
assert_rows(execute(cql, ks, "SELECT table_name, compaction FROM system_schema.tables WHERE keyspace_name='%s'"),
[cf, {"class": "org.apache.cassandra.db.compaction.SizeTieredCompactionStrategy",
"min_threshold": "7",
"max_threshold": "32"}])
# NOTE: The two tests, testCreateAlterNetworkTopologyWithDefaults() and
# testCreateSimpleAlterNTSDefaults() were not translated to this test
# framework because it doesn't create more than one DC - which these
# two tests try to test.
# Test {@link ConfigurationException} thrown on alter keyspace to no DC
# option in replication configuration.
# Reproduces CASSANDRA-12681 and Scylla #10036
def testAlterKeyspaceWithNoOptionThrowsConfigurationException(cql, test_keyspace, this_dc):
# Create keyspaces
with create_keyspace(cql, "replication={ 'class' : 'NetworkTopologyStrategy', '" + this_dc + "' : 3 }") as abc:
with create_keyspace(cql, "replication={ 'class' : 'NetworkTopologyStrategy', 'replication_factor' : 3 }") as xyz:
# Try to alter the created keyspace without any option
assert_invalid_throw(cql, xyz, ConfigurationException, "ALTER KEYSPACE %s WITH replication={ 'class' : 'SimpleStrategy' }")
assert_invalid_throw(cql, abc, ConfigurationException, "ALTER KEYSPACE %s WITH replication={ 'class' : 'NetworkTopologyStrategy' }")
# Make sure that the alter works as expected
execute(cql, abc, "ALTER KEYSPACE %s WITH replication={ 'class' : 'NetworkTopologyStrategy', '" + this_dc + "' : 2 }")
execute(cql, xyz, "ALTER KEYSPACE %s WITH replication={ 'class' : 'SimpleStrategy', 'replication_factor' : 2 }")
# Test {@link ConfigurationException} thrown when altering a keyspace to
# invalid DC option in replication configuration.
def testAlterKeyspaceWithNTSOnlyAcceptsConfiguredDataCenterNames(cql, test_keyspace, this_dc):
# Create a keyspace with expected DC name.
with create_keyspace(cql, "replication={ 'class' : 'NetworkTopologyStrategy', '" + this_dc + "' : 2 }") as ks:
# try modifying the keyspace
assert_invalid_throw_message_re(cql, ks, "Unrecognized strategy option {INVALID_DC} passed to .*NetworkTopologyStrategy for keyspace " + ks, ConfigurationException, "ALTER KEYSPACE %s WITH replication={ 'class' : 'NetworkTopologyStrategy', 'INVALID_DC' : 2 }")
execute(cql, ks, "ALTER KEYSPACE %s WITH replication = {'class' : 'NetworkTopologyStrategy', '" + this_dc + "' : 3 }")
# Mix valid and invalid, should throw an exception
assert_invalid_throw_message_re(cql, ks, "Unrecognized strategy option {INVALID_DC} passed to .*NetworkTopologyStrategy for keyspace " + ks, ConfigurationException, "ALTER KEYSPACE %s WITH replication={ 'class' : 'NetworkTopologyStrategy', '" + this_dc + "' : 2 , 'INVALID_DC': 1}")
def testAlterKeyspaceWithMultipleInstancesOfSameDCThrowsSyntaxException(cql, test_keyspace, this_dc):
# Create a keyspace
with create_keyspace(cql, "replication={ 'class' : 'NetworkTopologyStrategy', '" + this_dc + "' : 2 }") as ks:
# try modifying the keyspace
assert_invalid_throw(cql, ks, SyntaxException, "ALTER KEYSPACE %s WITH replication = {'class' : 'NetworkTopologyStrategy', '" + this_dc + "' : 2, '" + this_dc + "' : 3 }")
execute(cql, ks, "ALTER KEYSPACE %s WITH replication = {'class' : 'NetworkTopologyStrategy', '" + this_dc + "' : 3}")
# Test for bug of CASSANDRA-5232,
# migrated from cql_tests.py:TestCQL.alter_bug_test()
def testAlterStatementWithAdd(cql, test_keyspace):
with create_table(cql, test_keyspace, "(id int PRIMARY KEY, t text)") as table:
execute(cql, table, "UPDATE %s SET t = '111' WHERE id = 1")
execute(cql, table, "ALTER TABLE %s ADD l list<text>")
assert_rows(execute(cql, table, "SELECT * FROM %s"),
[1, None, "111"])
execute(cql, table, "ALTER TABLE %s ADD m map<int, text>")
assert_rows(execute(cql, table, "SELECT * FROM %s"),
[1, None, None, "111"])
# Test for CASSANDRA-7744,
# migrated from cql_tests.py:TestCQL.downgrade_to_compact_bug_test()
def testDowngradeToCompact(cql, test_keyspace):
with create_table(cql, test_keyspace, "(k int PRIMARY KEY, v set<text>)") as table:
execute(cql, table, "insert into %s (k, v) VALUES (0, {'f'})")
flush(cql, table)
execute(cql, table, "alter table %s drop v")
execute(cql, table, "alter table %s add v1 int")
# tests CASSANDRA-9565
def testDoubleWith(cql, test_keyspace):
stmts = [ "ALTER KEYSPACE WITH WITH DURABLE_WRITES = true",
f"ALTER KEYSPACE {test_keyspace} WITH WITH DURABLE_WRITES = true" ]
for stmt in stmts:
assert_invalid_throw(cql, test_keyspace, SyntaxException, stmt)
@pytest.mark.xfail(reason="Issue #8948")
def testAlterTableWithCompression(cql, test_keyspace):
with create_table(cql, test_keyspace, "(a text, b int, c int, primary key (a, b))") as table:
[ks, cf] = table.split('.')
# This first assert already reproduces #8948
assert_rows(execute(cql, table, "SELECT compression FROM system_schema.tables WHERE keyspace_name = ? and table_name = ?;", ks, cf),
[{"chunk_length_in_kb": "16", "class": "org.apache.cassandra.io.compress.LZ4Compressor"}])
execute(cql, table, "ALTER TABLE %s WITH compression = { 'class' : 'SnappyCompressor', 'chunk_length_in_kb' : 32 };")
assert_rows(execute(cql, table, "SELECT compression FROM system_schema.tables WHERE keyspace_name = ? and table_name = ?;", ks, cf),
[{"chunk_length_in_kb": "32", "class": "org.apache.cassandra.io.compress.SnappyCompressor"}])
execute(cql, table, "ALTER TABLE %s WITH compression = { 'class' : 'LZ4Compressor', 'chunk_length_in_kb' : 64 };")
assert_rows(execute(cql, table, "SELECT compression FROM system_schema.tables WHERE keyspace_name = ? and table_name = ?;", ks, cf),
[{"chunk_length_in_kb": "64", "class": "org.apache.cassandra.io.compress.LZ4Compressor"}])
execute(cql, table, "ALTER TABLE %s WITH compression = { 'class' : 'LZ4Compressor', 'min_compress_ratio' : 2 };")
assert_rows(execute(cql, table, "SELECT compression FROM system_schema.tables WHERE keyspace_name = ? and table_name = ?;", ks, cf),
[{"chunk_length_in_kb": "16", "class": "org.apache.cassandra.io.compress.LZ4Compressor", "min_compress_ratio": "2.0"}])
execute(cql, table, "ALTER TABLE %s WITH compression = { 'class' : 'LZ4Compressor', 'min_compress_ratio' : 1 };")
assert_rows(execute(cql, table, "SELECT compression FROM system_schema.tables WHERE keyspace_name = ? and table_name = ?;", ks, cf),
[{"chunk_length_in_kb": "16", "class": "org.apache.cassandra.io.compress.LZ4Compressor", "min_compress_ratio": "1.0"}])
execute(cql, table, "ALTER TABLE %s WITH compression = { 'class' : 'LZ4Compressor', 'min_compress_ratio' : 0 };")
assert_rows(execute(cql, table, "SELECT compression FROM system_schema.tables WHERE keyspace_name = ? and table_name = ?;", ks, cf),
[{"chunk_length_in_kb": "16", "class": "org.apache.cassandra.io.compress.LZ4Compressor"}])
execute(cql, table, "ALTER TABLE %s WITH compression = { 'class' : 'SnappyCompressor', 'chunk_length_in_kb' : 32 };")
execute(cql, table, "ALTER TABLE %s WITH compression = { 'enabled' : 'false'};")
assert_rows(execute(cql, table, "SELECT compression FROM system_schema.tables WHERE keyspace_name = ? and table_name = ?;", ks, cf),
[{"enabled": "false"}])
assert_invalid_throw_message(cql, table, "Missing sub-option 'class' for the 'compression' option.", ConfigurationException, "ALTER TABLE %s WITH compression = {'chunk_length_in_kb' : 32};")
assert_invalid_throw_message(cql, table, "The 'class' option must not be empty. To disable compression use 'enabled' : false", ConfigurationException, "ALTER TABLE %s WITH compression = { 'class' : ''};");
assert_invalid_throw_message(cql, table, "If the 'enabled' option is set to false no other options must be specified", ConfigurationException, "ALTER TABLE %s WITH compression = { 'enabled' : 'false', 'class' : 'SnappyCompressor'};")
assert_invalid_throw_message(cql, table, "The 'sstable_compression' option must not be used if the compression algorithm is already specified by the 'class' option", ConfigurationException, "ALTER TABLE %s WITH compression = { 'sstable_compression' : 'SnappyCompressor', 'class' : 'SnappyCompressor'};")
assert_invalid_throw_message(cql, table, "The 'chunk_length_kb' option must not be used if the chunk length is already specified by the 'chunk_length_in_kb' option", ConfigurationException, "ALTER TABLE %s WITH compression = { 'class' : 'SnappyCompressor', 'chunk_length_kb' : 32 , 'chunk_length_in_kb' : 32 };")
assert_invalid_throw_message(cql, table, "Invalid negative min_compress_ratio", ConfigurationException, "ALTER TABLE %s WITH compression = { 'class' : 'SnappyCompressor', 'min_compress_ratio' : -1 };")
assert_invalid_throw_message(cql, table, "min_compress_ratio can either be 0 or greater than or equal to 1", ConfigurationException, "ALTER TABLE %s WITH compression = { 'class' : 'SnappyCompressor', 'min_compress_ratio' : 0.5 };")
# Test for CASSANDRA-13337. Checks that dropping a column when a sstable contains only data for that column
# works properly.
def testAlterDropEmptySSTable(cql, test_keyspace):
with create_table(cql, test_keyspace, "(k int PRIMARY KEY, x int, y int)") as table:
execute(cql, table, "UPDATE %s SET x = 1 WHERE k = 0")
flush(cql, table)
execute(cql, table, "UPDATE %s SET x = 1, y = 1 WHERE k = 0")
flush(cql, table)
execute(cql, table, "ALTER TABLE %s DROP x")
compact(cql, table)
assert_rows(execute(cql, table, "SELECT * FROM %s"), [0, 1])
# Similarly to testAlterDropEmptySSTable, checks we don't return empty rows from queries (testAlterDropEmptySSTable
# tests the compaction case).
def testAlterOnlyColumnBehaviorWithFlush(cql, test_keyspace):
for flushAfterInsert in [True, False]:
with create_table(cql, test_keyspace, "(k int PRIMARY KEY, x int, y int)") as table:
execute(cql, table, "UPDATE %s SET x = 1 WHERE k = 0")
assert_rows(execute(cql, table, "SELECT * FROM %s"), [0, 1, None])
if flushAfterInsert:
flush(cql, table)
execute(cql, table, "ALTER TABLE %s DROP x")
assert_empty(execute(cql, table, "SELECT * FROM %s"))
# This test was modified from the original Cassandra test. Cassandra lists
# in the error message all the tables which need the UDT, but Scylla doesn't
# so we need a more direct test that doesn't rely on the error message.
# Reproduces CASSANDRA-15933
def testAlterTypeUsedInPartitionKey(cql, test_keyspace):
with create_type(cql, test_keyspace, "(v1 int)") as type1:
with create_type(cql, test_keyspace, f"(v1 frozen<{type1}>, v2 frozen<{type1}>)") as type2:
# frozen UDT used directly in a partition key
with create_table(cql, test_keyspace, f"(pk frozen<{type1}>, val int, PRIMARY KEY(pk))") as table1:
assert_invalid_message(cql, type1, table1, "ALTER TYPE %s ADD v2 int;")
# frozen UDT used in a frozen UDT used in a partition key
with create_table(cql, test_keyspace, f"(pk frozen<{type2}>, val int, PRIMARY KEY(pk))") as table2:
assert_invalid_message(cql, type1, table2, "ALTER TYPE %s ADD v2 int;")
# frozen UDT used in a frozen collection used in a partition key
with create_table(cql, test_keyspace, f"(pk frozen<list<frozen<{type1}>>>, val int, PRIMARY KEY(pk))") as table3:
assert_invalid_message(cql, type1, table3, "ALTER TYPE %s ADD v2 int;")