From f20ede79f97c02a0421bdbdc7848aefcc19e2fb0 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Thu, 9 Apr 2026 22:09:58 +0300 Subject: [PATCH] cql3: Move strict_is_not_null_in_views to cql_config Move strict_is_not_null_in_views option from db::config to cql_config via new view_restrictions sub-struct. This improves separation of concerns by keeping view-specific validation policies with other CQL configuration. Update prepare_view() to take view_restrictions reference instead of reaching into db::config, and update all callsites to pass the sub-struct. Signed-off-by: Pavel Emelyanov Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- cql3/cql_config.hh | 4 +++ cql3/restrictions/view_restrictions.hh | 32 ++++++++++++++++++++++++ cql3/statements/create_view_statement.cc | 9 +++---- cql3/statements/create_view_statement.hh | 3 ++- tools/schema_loader.cc | 2 +- 5 files changed, 43 insertions(+), 7 deletions(-) create mode 100644 cql3/restrictions/view_restrictions.hh diff --git a/cql3/cql_config.hh b/cql3/cql_config.hh index bd09a5f940..1bf8f5987d 100644 --- a/cql3/cql_config.hh +++ b/cql3/cql_config.hh @@ -13,6 +13,7 @@ #include "restrictions/restrictions_config.hh" #include "cql3/restrictions/replication_restrictions.hh" #include "cql3/restrictions/twcs_restrictions.hh" +#include "cql3/restrictions/view_restrictions.hh" #include "db/tri_mode_restriction.hh" #include "utils/updateable_value.hh" @@ -24,6 +25,7 @@ struct cql_config { restrictions::restrictions_config restrictions; replication_restrictions replication_restrictions; twcs_restrictions twcs_restrictions; + view_restrictions view_restrictions; utils::updateable_value select_internal_page_size; utils::updateable_value strict_allow_filtering; utils::updateable_value enable_parallelized_aggregation; @@ -35,6 +37,7 @@ struct cql_config { : restrictions(cfg) , replication_restrictions(cfg) , twcs_restrictions(cfg) + , view_restrictions(cfg) , select_internal_page_size(cfg.select_internal_page_size) , strict_allow_filtering(cfg.strict_allow_filtering) , enable_parallelized_aggregation(cfg.enable_parallelized_aggregation) @@ -47,6 +50,7 @@ struct cql_config { : restrictions(restrictions::restrictions_config::default_tag{}) , replication_restrictions(replication_restrictions::default_tag{}) , twcs_restrictions(twcs_restrictions::default_tag{}) + , view_restrictions(view_restrictions::default_tag{}) , select_internal_page_size(10000) , strict_allow_filtering(db::tri_mode_restriction(db::tri_mode_restriction_t::mode::WARN)) , enable_parallelized_aggregation(true) diff --git a/cql3/restrictions/view_restrictions.hh b/cql3/restrictions/view_restrictions.hh new file mode 100644 index 0000000000..d05e4726fc --- /dev/null +++ b/cql3/restrictions/view_restrictions.hh @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2019-present ScyllaDB + */ + +/* + * SPDX-License-Identifier: LicenseRef-ScyllaDB-Source-Available-1.1 + */ + +#pragma once + +#include "db/config.hh" +#include "db/tri_mode_restriction.hh" +#include "utils/updateable_value.hh" + +namespace db { class config; } + +namespace cql3 { + +struct view_restrictions { + utils::updateable_value strict_is_not_null_in_views; + + explicit view_restrictions(const db::config& cfg) + : strict_is_not_null_in_views(cfg.strict_is_not_null_in_views) + {} + + struct default_tag{}; + view_restrictions(default_tag) + : strict_is_not_null_in_views(db::tri_mode_restriction(db::tri_mode_restriction_t::mode::WARN)) + {} +}; + +} diff --git a/cql3/statements/create_view_statement.cc b/cql3/statements/create_view_statement.cc index 04841a446d..679408c238 100644 --- a/cql3/statements/create_view_statement.cc +++ b/cql3/statements/create_view_statement.cc @@ -33,7 +33,6 @@ #include "db/view/view.hh" #include "service/migration_manager.hh" #include "replica/database.hh" -#include "db/config.hh" #include "cql3/cql_config.hh" namespace cql3 { @@ -107,7 +106,7 @@ static bool validate_primary_key( return new_non_pk_column; } -std::pair create_view_statement::prepare_view(data_dictionary::database db, locator::token_metadata_ptr tmptr) const { +std::pair create_view_statement::prepare_view(data_dictionary::database db, locator::token_metadata_ptr tmptr, const view_restrictions& vr) const { // We need to make sure that: // - materialized view name is valid // - primary key includes all columns in base table's primary key @@ -325,7 +324,7 @@ std::pair create_view_statement::prepare_view( } if (!invalid_not_null_column_names.empty() && - db.get_config().strict_is_not_null_in_views() == db::tri_mode_restriction_t::mode::TRUE) { + vr.strict_is_not_null_in_views() == db::tri_mode_restriction_t::mode::TRUE) { throw exceptions::invalid_request_exception( fmt::format("The IS NOT NULL restriction is allowed only columns which are part of the view's primary key," " found columns: {}. The flag strict_is_not_null_in_views can be used to turn this error " @@ -334,7 +333,7 @@ std::pair create_view_statement::prepare_view( } if (!invalid_not_null_column_names.empty() && - db.get_config().strict_is_not_null_in_views() == db::tri_mode_restriction_t::mode::WARN) { + vr.strict_is_not_null_in_views() == db::tri_mode_restriction_t::mode::WARN) { sstring warning_text = fmt::format( "The IS NOT NULL restriction is allowed only columns which are part of the view's primary key," " found columns: {}. Restrictions on these columns will be silently ignored. " @@ -402,7 +401,7 @@ std::pair create_view_statement::prepare_view( future, utils::chunked_vector, cql3::cql_warnings_vec>> create_view_statement::prepare_schema_mutations(query_processor& qp, const query_options&, api::timestamp_type ts) const { utils::chunked_vector m; - auto [definition, warnings] = prepare_view(qp.db(), qp.proxy().get_token_metadata_ptr()); + auto [definition, warnings] = prepare_view(qp.db(), qp.proxy().get_token_metadata_ptr(), qp.get_cql_config().view_restrictions); try { m = co_await service::prepare_new_view_announcement(qp.proxy(), std::move(definition), ts); } catch (const exceptions::already_exists_exception& e) { diff --git a/cql3/statements/create_view_statement.hh b/cql3/statements/create_view_statement.hh index 6cc125b94e..efeb135a72 100644 --- a/cql3/statements/create_view_statement.hh +++ b/cql3/statements/create_view_statement.hh @@ -19,6 +19,7 @@ namespace cql3 { class query_processor; +struct view_restrictions; class relation; namespace selection { @@ -48,7 +49,7 @@ public: std::vector<::shared_ptr> clustering_keys, bool if_not_exists); - std::pair prepare_view(data_dictionary::database db, locator::token_metadata_ptr tmptr) const; + std::pair prepare_view(data_dictionary::database db, locator::token_metadata_ptr tmptr, const view_restrictions& vr) const; auto& properties() { return _properties; diff --git a/tools/schema_loader.cc b/tools/schema_loader.cc index 31bd3a0a1b..c113eaa2ac 100644 --- a/tools/schema_loader.cc +++ b/tools/schema_loader.cc @@ -321,7 +321,7 @@ std::vector do_load_schemas(const db::config& cfg, std::string_view } real_db.tables.emplace_back(dd_impl, dd_impl.unwrap(ks), std::move(schema), true); } else if (auto p = dynamic_cast(statement)) { - auto&& [view, warnings] = p->prepare_view(db, token_metadata.local().get()); + auto&& [view, warnings] = p->prepare_view(db, token_metadata.local().get(), cql3::default_cql_config.view_restrictions); auto it = std::find_if(real_db.tables.begin(), real_db.tables.end(), [&] (const table& t) { return t.schema->ks_name() == view->ks_name() && t.schema->cf_name() == view->cf_name(); }); if (it != real_db.tables.end()) { continue; // view already exists