This is an automated email from the ASF dual-hosted git repository. adelapena pushed a commit to branch cassandra-5.0 in repository https://gitbox.apache.org/repos/asf/cassandra.git
The following commit(s) were added to refs/heads/cassandra-5.0 by this push: new 7482d88f48 Add guardrail for vector dimensions 7482d88f48 is described below commit 7482d88f48662480c6879b4e500bcdf93c78e5e0 Author: Andrés de la Peña <a.penya.gar...@gmail.com> AuthorDate: Mon Aug 7 12:46:08 2023 +0100 Add guardrail for vector dimensions patch by Andrés de la Peña; reviewed by Brandon Williams and Maxwell Guo for CASSANDRA-18730 --- CHANGES.txt | 1 + NEWS.txt | 1 + conf/cassandra.yaml | 5 + src/java/org/apache/cassandra/config/Config.java | 2 + .../apache/cassandra/config/GuardrailsOptions.java | 26 +++ src/java/org/apache/cassandra/cql3/CQL3Type.java | 53 ++++++ .../statements/schema/AlterTableStatement.java | 7 + .../cql3/statements/schema/AlterTypeStatement.java | 1 + .../statements/schema/CreateTableStatement.java | 15 +- .../statements/schema/CreateTypeStatement.java | 5 + .../apache/cassandra/db/guardrails/Guardrails.java | 30 ++++ .../cassandra/db/guardrails/GuardrailsConfig.java | 10 ++ .../cassandra/db/guardrails/GuardrailsMBean.java | 16 ++ .../guardrails/GuardrailVectorDimensionsTest.java | 184 +++++++++++++++++++++ 14 files changed, 350 insertions(+), 6 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index 0de34d2bf4..7528daf808 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,4 +1,5 @@ 5.0 + * Add guardrail for vector dimensions (CASSANDRA-18730) * Upgraded Netty to 4.1.96, added BouncyCastle dependency (CASSANDRA-17992) * Fix for (unsupported) big endian unaligned architecture, eg s390x (CASSANDRA-17723) * CIDR filtering authorizer (CASSANDRA-18592) diff --git a/NEWS.txt b/NEWS.txt index 9b8441f857..788e4cadef 100644 --- a/NEWS.txt +++ b/NEWS.txt @@ -116,6 +116,7 @@ New features - Column value size - Partition size - Partition tombstones + - Vector dimensions - It is possible to list ephemeral snapshots by nodetool listsnaphots command when flag "-e" is specified. - Added a new flag to `nodetool profileload` and JMX endpoint to set up recurring profile load generation on specified intervals (see CASSANDRA-17821) diff --git a/conf/cassandra.yaml b/conf/cassandra.yaml index 26d3579f03..4d6d4f1d42 100644 --- a/conf/cassandra.yaml +++ b/conf/cassandra.yaml @@ -1989,6 +1989,11 @@ drop_compact_storage_enabled: false # fields_per_udt_warn_threshold: -1 # fields_per_udt_fail_threshold: -1 # +# Guardrail to warn or fail when creating a vector column with more dimensions than threshold. +# Default -1 to disable. +# vector_dimensions_warn_threshold: -1 +# vector_dimensions_fail_threshold: -1 +# # Guardrail to indicate whether or not users are allowed to use ALTER TABLE commands to make column changes to tables # alter_table_enabled: true # diff --git a/src/java/org/apache/cassandra/config/Config.java b/src/java/org/apache/cassandra/config/Config.java index 831bf93cfc..2f6408f3fd 100644 --- a/src/java/org/apache/cassandra/config/Config.java +++ b/src/java/org/apache/cassandra/config/Config.java @@ -892,6 +892,8 @@ public class Config public volatile int items_per_collection_fail_threshold = -1; public volatile int fields_per_udt_warn_threshold = -1; public volatile int fields_per_udt_fail_threshold = -1; + public volatile int vector_dimensions_warn_threshold = -1; + public volatile int vector_dimensions_fail_threshold = -1; public volatile int data_disk_usage_percentage_warn_threshold = -1; public volatile int data_disk_usage_percentage_fail_threshold = -1; public volatile DataStorageSpec.LongBytesBound data_disk_usage_max_disk_size = null; diff --git a/src/java/org/apache/cassandra/config/GuardrailsOptions.java b/src/java/org/apache/cassandra/config/GuardrailsOptions.java index f58408e8b2..b0cb259c26 100644 --- a/src/java/org/apache/cassandra/config/GuardrailsOptions.java +++ b/src/java/org/apache/cassandra/config/GuardrailsOptions.java @@ -82,6 +82,7 @@ public class GuardrailsOptions implements GuardrailsConfig validateSizeThreshold(config.collection_size_warn_threshold, config.collection_size_fail_threshold, false, "collection_size"); validateMaxIntThreshold(config.items_per_collection_warn_threshold, config.items_per_collection_fail_threshold, "items_per_collection"); validateMaxIntThreshold(config.fields_per_udt_warn_threshold, config.fields_per_udt_fail_threshold, "fields_per_udt"); + validateMaxIntThreshold(config.vector_dimensions_warn_threshold, config.vector_dimensions_fail_threshold, "vector_dimensions"); validatePercentageThreshold(config.data_disk_usage_percentage_warn_threshold, config.data_disk_usage_percentage_fail_threshold, "data_disk_usage_percentage"); validateDataDiskUsageMaxDiskSize(config.data_disk_usage_max_disk_size); validateMinRFThreshold(config.minimum_replication_factor_warn_threshold, config.minimum_replication_factor_fail_threshold); @@ -697,6 +698,31 @@ public class GuardrailsOptions implements GuardrailsConfig x -> config.fields_per_udt_fail_threshold = x); } + @Override + public int getVectorDimensionsWarnThreshold() + { + return config.vector_dimensions_warn_threshold; + } + + @Override + public int getVectorDimensionsFailThreshold() + { + return config.vector_dimensions_fail_threshold; + } + + public void setVectorDimensionsThreshold(int warn, int fail) + { + validateMaxIntThreshold(warn, fail, "vector_dimensions"); + updatePropertyWithLogging("vector_dimensions_warn_threshold", + warn, + () -> config.vector_dimensions_warn_threshold, + x -> config.vector_dimensions_warn_threshold = x); + updatePropertyWithLogging("vector_dimensions_fail_threshold", + fail, + () -> config.vector_dimensions_fail_threshold, + x -> config.vector_dimensions_fail_threshold = x); + } + public int getDataDiskUsagePercentageWarnThreshold() { return config.data_disk_usage_percentage_warn_threshold; diff --git a/src/java/org/apache/cassandra/cql3/CQL3Type.java b/src/java/org/apache/cassandra/cql3/CQL3Type.java index acb8bc97e2..074a8e515e 100644 --- a/src/java/org/apache/cassandra/cql3/CQL3Type.java +++ b/src/java/org/apache/cassandra/cql3/CQL3Type.java @@ -24,6 +24,7 @@ import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.apache.cassandra.db.guardrails.Guardrails; import org.apache.cassandra.db.marshal.*; import org.apache.cassandra.db.marshal.CollectionType.Kind; import org.apache.cassandra.exceptions.InvalidRequestException; @@ -35,6 +36,7 @@ import org.apache.cassandra.schema.SchemaConstants; import org.apache.cassandra.schema.Types; import org.apache.cassandra.serializers.CollectionSerializer; import org.apache.cassandra.serializers.MarshalException; +import org.apache.cassandra.service.ClientState; import org.apache.cassandra.utils.ByteBufferUtil; import static java.util.stream.Collectors.toList; @@ -53,6 +55,11 @@ public interface CQL3Type return false; } + default boolean isVector() + { + return false; + } + public AbstractType<?> getType(); /** @@ -528,6 +535,11 @@ public interface CQL3Type this.type = VectorType.getInstance(elementType, dimensions); } + public boolean isVector() + { + return true; + } + @Override public VectorType<?> getType() { @@ -622,6 +634,8 @@ public interface CQL3Type throw new InvalidRequestException(message); } + public abstract void validate(ClientState state, String name); + public CQL3Type prepare(String keyspace) { KeyspaceMetadata ksm = Schema.instance.getKeyspaceMetadata(keyspace); @@ -687,6 +701,16 @@ public interface CQL3Type this.type = type; } + @Override + public void validate(ClientState state, String name) + { + if (type.isVector()) + { + int dimensions = ((Vector) type).getType().dimension; + Guardrails.vectorDimensions.guard(dimensions, name, false, state); + } + } + public CQL3Type prepare(String keyspace, Types udts) throws InvalidRequestException { return type; @@ -754,6 +778,16 @@ public interface CQL3Type return true; } + @Override + public void validate(ClientState state, String name) + { + if (keys != null) + keys.validate(state, name); + + if (values != null) + values.validate(state, name); + } + public CQL3Type prepare(String keyspace, Types udts) throws InvalidRequestException { return prepare(keyspace, udts, false); @@ -861,6 +895,12 @@ public interface CQL3Type return this; } + @Override + public void validate(ClientState state, String name) + { + Guardrails.vectorDimensions.guard(dimension, name, false, state); + } + @Override public CQL3Type prepare(String keyspace, Types udts) throws InvalidRequestException { @@ -896,6 +936,12 @@ public interface CQL3Type return new RawUT(name, true); } + @Override + public void validate(ClientState state, String name) + { + // nothing to do here + } + public CQL3Type prepare(String keyspace, Types udts) throws InvalidRequestException { if (name.hasKeyspace()) @@ -969,6 +1015,13 @@ public interface CQL3Type return this; } + @Override + public void validate(ClientState state, String name) + { + for (CQL3Type.Raw t : types) + t.validate(state, name); + } + public CQL3Type prepare(String keyspace, Types udts) throws InvalidRequestException { List<AbstractType<?>> ts = new ArrayList<>(types.size()); diff --git a/src/java/org/apache/cassandra/cql3/statements/schema/AlterTableStatement.java b/src/java/org/apache/cassandra/cql3/statements/schema/AlterTableStatement.java index 81f096a6e7..ee5c328180 100644 --- a/src/java/org/apache/cassandra/cql3/statements/schema/AlterTableStatement.java +++ b/src/java/org/apache/cassandra/cql3/statements/schema/AlterTableStatement.java @@ -267,6 +267,13 @@ public abstract class AlterTableStatement extends AlterSchemaStatement this.ifColumnNotExists = ifColumnNotExists; } + @Override + public void validate(ClientState state) + { + super.validate(state); + newColumns.forEach(c -> c.type.validate(state, "Column " + c.name)); + } + public KeyspaceMetadata apply(KeyspaceMetadata keyspace, TableMetadata table) { Guardrails.alterTableEnabled.ensureEnabled("ALTER TABLE changing columns", state); diff --git a/src/java/org/apache/cassandra/cql3/statements/schema/AlterTypeStatement.java b/src/java/org/apache/cassandra/cql3/statements/schema/AlterTypeStatement.java index 89cb990ae2..00fbf60fef 100644 --- a/src/java/org/apache/cassandra/cql3/statements/schema/AlterTypeStatement.java +++ b/src/java/org/apache/cassandra/cql3/statements/schema/AlterTypeStatement.java @@ -147,6 +147,7 @@ public abstract class AlterTypeStatement extends AlterSchemaStatement } Guardrails.fieldsPerUDT.guard(userType.size() + 1, userType.getNameAsString(), false, state); + type.validate(state, "Field " + fieldName); List<FieldIdentifier> fieldNames = new ArrayList<>(userType.fieldNames()); fieldNames.add(fieldName); List<AbstractType<?>> fieldTypes = new ArrayList<>(userType.fieldTypes()); fieldTypes.add(fieldType); diff --git a/src/java/org/apache/cassandra/cql3/statements/schema/CreateTableStatement.java b/src/java/org/apache/cassandra/cql3/statements/schema/CreateTableStatement.java index 8d0c0b4d2c..c0a1783221 100644 --- a/src/java/org/apache/cassandra/cql3/statements/schema/CreateTableStatement.java +++ b/src/java/org/apache/cassandra/cql3/statements/schema/CreateTableStatement.java @@ -152,12 +152,7 @@ public final class CreateTableStatement extends AlterSchemaStatement validateDefaultTimeToLive(attrs.asNewTableParams()); - // Verify that dynamic data masking is enabled if there are masked columns - for (ColumnProperties.Raw raw : rawColumns.values()) - { - if (raw.rawMask != null) - ColumnMask.ensureEnabled(); - } + rawColumns.forEach((name, raw) -> raw.validate(state, name)); } SchemaChange schemaChangeEvent(KeyspacesDiff diff) @@ -604,6 +599,14 @@ public final class CreateTableStatement extends AlterSchemaStatement this.rawMask = rawMask; } + public void validate(ClientState state, ColumnIdentifier name) + { + rawType.validate(state, "Column " + name); + + if (rawMask != null) + ColumnMask.ensureEnabled(); + } + public ColumnProperties prepare(String keyspace, String table, ColumnIdentifier column, Types udts) { CQL3Type cqlType = rawType.prepare(keyspace, udts); diff --git a/src/java/org/apache/cassandra/cql3/statements/schema/CreateTypeStatement.java b/src/java/org/apache/cassandra/cql3/statements/schema/CreateTypeStatement.java index e015c34ede..d76c8089f6 100644 --- a/src/java/org/apache/cassandra/cql3/statements/schema/CreateTypeStatement.java +++ b/src/java/org/apache/cassandra/cql3/statements/schema/CreateTypeStatement.java @@ -68,6 +68,11 @@ public final class CreateTypeStatement extends AlterSchemaStatement super.validate(state); Guardrails.fieldsPerUDT.guard(fieldNames.size(), typeName, false, state); + + for (int i = 0; i < rawFieldTypes.size(); i++) + { + rawFieldTypes.get(i).validate(state, "Field " + fieldNames.get(i)); + } } public Keyspaces apply(Keyspaces schema) diff --git a/src/java/org/apache/cassandra/db/guardrails/Guardrails.java b/src/java/org/apache/cassandra/db/guardrails/Guardrails.java index 4f736337e8..4eb1084e51 100644 --- a/src/java/org/apache/cassandra/db/guardrails/Guardrails.java +++ b/src/java/org/apache/cassandra/db/guardrails/Guardrails.java @@ -385,6 +385,18 @@ public final class Guardrails implements GuardrailsMBean : format("User types cannot have more than %s columns, but %s provided for user type %s.", threshold, value, what)); + /** + * Guardrail on the number of dimensions of vector columns. + */ + public static final MaxThreshold vectorDimensions = + new MaxThreshold("vector_dimensions", + null, + state -> CONFIG_PROVIDER.getOrCreate(state).getVectorDimensionsWarnThreshold(), + state -> CONFIG_PROVIDER.getOrCreate(state).getVectorDimensionsFailThreshold(), + (isWarning, what, value, threshold) -> + format("%s has a vector of %s dimensions, this exceeds the %s threshold of %s.", + what, value, isWarning ? "warning" : "failure", threshold)); + /** * Guardrail on the data disk usage on the local node, used by a periodic task to calculate and propagate that status. * See {@link org.apache.cassandra.service.disk.usage.DiskUsageMonitor} and {@link DiskUsageBroadcaster}. @@ -1043,6 +1055,24 @@ public final class Guardrails implements GuardrailsMBean DEFAULT_CONFIG.setFieldsPerUDTThreshold(warn, fail); } + @Override + public int getVectorDimensionsWarnThreshold() + { + return DEFAULT_CONFIG.getVectorDimensionsWarnThreshold(); + } + + @Override + public int getVectorDimensionsFailThreshold() + { + return DEFAULT_CONFIG.getVectorDimensionsFailThreshold(); + } + + @Override + public void setVectorDimensionsThreshold(int warn, int fail) + { + DEFAULT_CONFIG.setVectorDimensionsThreshold(warn, fail); + } + @Override public int getMaximumReplicationFactorWarnThreshold() { diff --git a/src/java/org/apache/cassandra/db/guardrails/GuardrailsConfig.java b/src/java/org/apache/cassandra/db/guardrails/GuardrailsConfig.java index 9639066595..ac6e5842e1 100644 --- a/src/java/org/apache/cassandra/db/guardrails/GuardrailsConfig.java +++ b/src/java/org/apache/cassandra/db/guardrails/GuardrailsConfig.java @@ -304,6 +304,16 @@ public interface GuardrailsConfig */ int getFieldsPerUDTFailThreshold(); + /** + * @return The threshold to warn when creating a vector with more dimensions than threshold. + */ + int getVectorDimensionsWarnThreshold(); + + /** + * @return The threshold to fail when creating a vector with more dimensions than threshold. + */ + int getVectorDimensionsFailThreshold(); + /** * @return The threshold to warn when local disk usage percentage exceeds that threshold. * Allowed values are in the range {@code [1, 100]}, and -1 means disabled. diff --git a/src/java/org/apache/cassandra/db/guardrails/GuardrailsMBean.java b/src/java/org/apache/cassandra/db/guardrails/GuardrailsMBean.java index 0c8ff344ab..f05ae4366a 100644 --- a/src/java/org/apache/cassandra/db/guardrails/GuardrailsMBean.java +++ b/src/java/org/apache/cassandra/db/guardrails/GuardrailsMBean.java @@ -597,6 +597,22 @@ public interface GuardrailsMBean */ void setFieldsPerUDTThreshold(int warn, int fail); + /** + * @return The threshold to warn when creating a vector with more dimensions than threshold. + */ + int getVectorDimensionsWarnThreshold(); + + /** + * @return The threshold to fail when creating a vector with more dimensions than threshold. + */ + int getVectorDimensionsFailThreshold(); + + /** + * @param warn The threshold to warn when creating a vector with more dimensions than threshold. + * @param fail The threshold to prevent creating a vector with more dimensions than threshold. + */ + void setVectorDimensionsThreshold(int warn, int fail); + /** * @return The threshold to warn when local data disk usage percentage exceeds that threshold. * Allowed values are in the range {@code [1, 100]}, and -1 means disabled. diff --git a/test/unit/org/apache/cassandra/db/guardrails/GuardrailVectorDimensionsTest.java b/test/unit/org/apache/cassandra/db/guardrails/GuardrailVectorDimensionsTest.java new file mode 100644 index 0000000000..45727272b2 --- /dev/null +++ b/test/unit/org/apache/cassandra/db/guardrails/GuardrailVectorDimensionsTest.java @@ -0,0 +1,184 @@ +/* + * 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. + */ + +package org.apache.cassandra.db.guardrails; + +import java.util.function.Supplier; + +import org.junit.Test; + +import static java.lang.String.format; + +/** + * Tests the guardrail for the number of dimensions of a vector, {@link Guardrails#vectorDimensions}. + */ +public class GuardrailVectorDimensionsTest extends ThresholdTester +{ + private static final int WARN_THRESHOLD = 2; + private static final int FAIL_THRESHOLD = 4; + + public GuardrailVectorDimensionsTest() + { + super(WARN_THRESHOLD, + FAIL_THRESHOLD, + Guardrails.vectorDimensions, + Guardrails::setVectorDimensionsThreshold, + Guardrails::getVectorDimensionsWarnThreshold, + Guardrails::getVectorDimensionsFailThreshold); + } + + @Test + public void testCreateTable() throws Throwable + { + // different poisitions (partition key, clustering key, static column, regular column) + testCreateTable("CREATE TABLE %s (v vector<int, %%d> PRIMARY KEY)"); + testCreateTable("CREATE TABLE %s (v vector<int, %%d>, c int, PRIMARY KEY(v, c))"); + testCreateTable("CREATE TABLE %s (v vector<int, %%d>, c int, PRIMARY KEY((v, c)))"); + testCreateTable("CREATE TABLE %s (k int, v vector<int, %%d>, PRIMARY KEY(k, v))"); + testCreateTable("CREATE TABLE %s (k int, c int, v vector<int, %%d>, PRIMARY KEY(k, c, v))"); + testCreateTable("CREATE TABLE %s (k int, c int, v vector<int, %%d> static, PRIMARY KEY(k, c))"); + testCreateTable("CREATE TABLE %s (k int PRIMARY KEY, v vector<int, %%d>)"); + + // multivalued data types + testCreateTable("CREATE TABLE %s (k int PRIMARY KEY, v list<vector<int, %%d>>)"); + testCreateTable("CREATE TABLE %s (k int PRIMARY KEY, v set<vector<int, %%d>>)"); + testCreateTable("CREATE TABLE %s (k int PRIMARY KEY, v map<int, vector<int, %%d>>)"); + testCreateTable("CREATE TABLE %s (k int PRIMARY KEY, v map<vector<int, %%d>, int>)"); + testCreateTable("CREATE TABLE %s (k int PRIMARY KEY, v tuple<vector<int, %%d>, int>)"); + testCreateTable("CREATE TABLE %s (k int PRIMARY KEY, v tuple<int, vector<int, %%d>>)"); + + // nested multivalued data types + testCreateTable("CREATE TABLE %s (k int PRIMARY KEY, v set<frozen<list<vector<int, %%d>>>>)"); + testCreateTable("CREATE TABLE %s (k int PRIMARY KEY, v list<frozen<set<vector<int, %%d>>>>)"); + testCreateTable("CREATE TABLE %s (k int PRIMARY KEY, v map<int, frozen<set<vector<int, %%d>>>>)"); + testCreateTable("CREATE TABLE %s (k int PRIMARY KEY, v map<frozen<set<vector<int, %%d>>>, int>)"); + testCreateTable("CREATE TABLE %s (k int PRIMARY KEY, v tuple<frozen<tuple<vector<int, %%d>, int>>, int>)"); + } + + private void testCreateTable(String query) throws Throwable + { + testColumn(() -> format(query, createTableName())); + } + + @Test + public void testCreateType() throws Throwable + { + testCreateType("CREATE TYPE %s (c int, v vector<int, %%d>)"); + testCreateType("CREATE TYPE %s (c int, v list<vector<int, %%d>>)"); + testCreateType("CREATE TYPE %s (c int, v set<vector<int, %%d>>)"); + testCreateType("CREATE TYPE %s (c int, v map<int, vector<int, %%d>>)"); + testCreateType("CREATE TYPE %s (c int, v map<vector<int, %%d>, int>)"); + testCreateType("CREATE TYPE %s (c int, v tuple<vector<int, %%d>, int>)"); + testCreateType("CREATE TYPE %s (c int, v tuple<int, vector<int, %%d>>)"); + } + + private void testCreateType(String query) throws Throwable + { + testField(() -> format(query, createTypeName())); + } + + @Test + public void testAlterTable() throws Throwable + { + testAlterTable("ALTER TABLE %s ADD v vector<int, %%d>"); + testAlterTable("ALTER TABLE %s ADD v list<vector<int, %%d>>"); + testAlterTable("ALTER TABLE %s ADD v set<vector<int, %%d>>"); + testAlterTable("ALTER TABLE %s ADD v map<int, vector<int, %%d>>"); + testAlterTable("ALTER TABLE %s ADD v map<vector<int, %%d>, int>"); + testAlterTable("ALTER TABLE %s ADD v tuple<vector<int, %%d>, int>"); + testAlterTable("ALTER TABLE %s ADD v tuple<int, vector<int, %%d>>"); + } + + private void testAlterTable(String query) throws Throwable + { + testColumn(() -> { + createTable("CREATE TABLE %s (k int PRIMARY KEY)"); + return format(query, currentTable()); + }); + } + + @Test + public void testAlterType() throws Throwable + { + testAlterType("ALTER TYPE %s ADD v vector<int, %%d>"); + testAlterType("ALTER TYPE %s ADD v list<vector<int, %%d>>"); + testAlterType("ALTER TYPE %s ADD v set<vector<int, %%d>>"); + testAlterType("ALTER TYPE %s ADD v map<int, vector<int, %%d>>"); + testAlterType("ALTER TYPE %s ADD v map<vector<int, %%d>, int>"); + testAlterType("ALTER TYPE %s ADD v tuple<vector<int, %%d>, int>"); + testAlterType("ALTER TYPE %s ADD v tuple<int, vector<int, %%d>>"); + } + + private void testAlterType(String query) throws Throwable + { + testField(() -> { + String name = createType("CREATE TYPE %s (c int)"); + return format(query, name); + }); + } + + @Test + public void testExcludedUsers() throws Throwable + { + testExcludedUsers(() -> format("CREATE TABLE %s (k int PRIMARY KEY, v vector<int, 1000>)", createTableName()), + () -> format("CREATE TYPE %s (c int, v vector<int, 1000>)", createTypeName()), + () -> format("ALTER TABLE %s ADD v vector<int, 1000>", + createTable("CREATE TABLE %s (k int PRIMARY KEY)")), + () -> format("ALTER TYPE %s ADD v vector<int, 1000>", + createType("CREATE TYPE %s (c int)"))); + } + + private void testColumn(Supplier<String> query) throws Throwable + { + testGuardrail(query, "Column v"); + } + + private void testField(Supplier<String> query) throws Throwable + { + testGuardrail(query, "Field v"); + } + + private void testGuardrail(Supplier<String> query, String element) throws Throwable + { + assertValid(query.get(), 1); + assertValid(query.get(), WARN_THRESHOLD); + assertWarns(query.get(), element, WARN_THRESHOLD + 1); + assertWarns(query.get(), element, FAIL_THRESHOLD); + assertFails(query.get(), element, FAIL_THRESHOLD + 1); + assertFails(query.get(), element, Integer.MAX_VALUE); + } + + private void assertValid(String query, int dimensions) throws Throwable + { + super.assertValid(format(query, dimensions)); + } + + private void assertWarns(String query, String what, int dimensions) throws Throwable + { + assertWarns(format(query, dimensions), + format(what + " has a vector of %s dimensions, this exceeds the warning threshold of %s.", + dimensions, WARN_THRESHOLD)); + } + + private void assertFails(String query, String what, int dimensions) throws Throwable + { + assertFails(format(query, dimensions), + format(what + " has a vector of %s dimensions, this exceeds the failure threshold of %s.", + dimensions, FAIL_THRESHOLD)); + } +} --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@cassandra.apache.org For additional commands, e-mail: commits-h...@cassandra.apache.org