From ffe1029b7c7bd9861aaee3e4dbcf44b9f547fec2 Mon Sep 17 00:00:00 2001 From: Nadav Har'El Date: Sun, 5 Apr 2026 10:23:11 +0300 Subject: [PATCH] alternator: prevent adding GSI conflicting with a vector index All the "indexes" we implement in Alternator - GSI, LSI and the new vector index - share the same IndexName namespace, which we'll use in Query to refer to the index. In the previous patch we already prevented adding a vector index with the same name as an existing GSI or LSI. In this patch we also prevent the reverse - adding a GSI with the name of an existing vector index. Additionally, one cannot add a GSI on a key that is already the key of a vector index: The types conflict: The key of a vector index must be a vector column, while the key of a GSI must have a standard key type (string, binary or number). We have tests for this later, this the big test patch. --- alternator/executor.cc | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/alternator/executor.cc b/alternator/executor.cc index e293b9cd9b..f490629bbf 100644 --- a/alternator/executor.cc +++ b/alternator/executor.cc @@ -2246,17 +2246,20 @@ future executor::create_table(client_state& clien // columns of the base table or any of its prior GSIs or LSIs, the type // given in AttributeDefinitions must match the type of the existing key - // otherwise Alternator will not know which type to enforce in new writes. +// Also, if the table already has vector indexes, their key attributes cannot +// be redefined in AttributeDefinitions with a non-vector type. // This function checks for such conflicts. It assumes that the structure of // the given attribute_definitions was already validated (with // validate_attribute_definitions()). // This function should be called multiple times - once for the base schema // and once for each of its views (existing GSIs and LSIs on this table). static void check_attribute_definitions_conflicts(const rjson::value& attribute_definitions, const schema& schema) { - for (auto& def : schema.primary_key_columns()) { - std::string def_type = type_to_string(def.type); - for (auto it = attribute_definitions.Begin(); it != attribute_definitions.End(); ++it) { - const rjson::value& attribute_info = *it; - if (rjson::to_string_view(attribute_info["AttributeName"]) == def.name_as_text()) { + for (auto it = attribute_definitions.Begin(); it != attribute_definitions.End(); ++it) { + const rjson::value& attribute_info = *it; + std::string_view attribute_name = rjson::to_string_view(attribute_info["AttributeName"]); + for (auto& def : schema.primary_key_columns()) { + if (attribute_name == def.name_as_text()) { + auto def_type = type_to_string(def.type); std::string_view type = rjson::to_string_view(attribute_info["AttributeType"]); if (type != def_type) { throw api_error::validation(fmt::format("AttributeDefinitions redefined {} to {} already a key attribute of type {} in this table", def.name_as_text(), type, def_type)); @@ -2264,6 +2267,12 @@ future executor::create_table(client_state& clien break; } } + // Additionally, if we have a vector index, its key attribute is + // required to have a vector type, and cannot be listed in + // AttributeDefinitions with a non-vector key type. + if (has_vector_index_on_attribute(schema, attribute_name)) { + throw api_error::validation(fmt::format("AttributeDefinitions redefines {} but already a key of a vector index in this table", attribute_name)); + } } } @@ -2522,6 +2531,10 @@ future executor::update_table(client_state& clien co_return api_error::validation(fmt::format( "LSI {} already exists in table {}, can't use same name for GSI", index_name, table_name)); } + if (tab->has_index(sstring(index_name))) { + co_return api_error::validation(fmt::format( + "Vector index {} already exists in table {}, cannot reuse the name for a GSI", index_name, table_name)); + } try { locator::assert_rf_rack_valid_keyspace(keyspace_name, p.local().local_db().get_token_metadata_ptr(), p.local().local_db().find_keyspace(keyspace_name).get_replication_strategy());