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 <xemul@scylladb.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
Pavel Emelyanov
2026-04-09 22:09:58 +03:00
parent 027c91f45e
commit f20ede79f9
5 changed files with 43 additions and 7 deletions

View File

@@ -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<uint32_t> select_internal_page_size;
utils::updateable_value<db::tri_mode_restriction> strict_allow_filtering;
utils::updateable_value<bool> 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)

View File

@@ -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<db::tri_mode_restriction> 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))
{}
};
}

View File

@@ -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<view_ptr, cql3::cql_warnings_vec> create_view_statement::prepare_view(data_dictionary::database db, locator::token_metadata_ptr tmptr) const {
std::pair<view_ptr, cql3::cql_warnings_vec> 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<view_ptr, cql3::cql_warnings_vec> 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<view_ptr, cql3::cql_warnings_vec> 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<view_ptr, cql3::cql_warnings_vec> create_view_statement::prepare_view(
future<std::tuple<::shared_ptr<cql_transport::event::schema_change>, utils::chunked_vector<mutation>, cql3::cql_warnings_vec>>
create_view_statement::prepare_schema_mutations(query_processor& qp, const query_options&, api::timestamp_type ts) const {
utils::chunked_vector<mutation> 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) {

View File

@@ -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<cql3::column_identifier::raw>> clustering_keys,
bool if_not_exists);
std::pair<view_ptr, cql3::cql_warnings_vec> prepare_view(data_dictionary::database db, locator::token_metadata_ptr tmptr) const;
std::pair<view_ptr, cql3::cql_warnings_vec> prepare_view(data_dictionary::database db, locator::token_metadata_ptr tmptr, const view_restrictions& vr) const;
auto& properties() {
return _properties;

View File

@@ -321,7 +321,7 @@ std::vector<schema_ptr> 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<cql3::statements::create_view_statement*>(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