Skip to content

Commit ff37ec8

Browse files
authored
Merge pull request #1875 from Altinity/backports/25.8/104881
Backport of ClickHouse#104881 to 25.8: Use explicit flag for secondary on cluster queries
2 parents 32c9e33 + 2fa783d commit ff37ec8

13 files changed

Lines changed: 32 additions & 23 deletions

src/Backups/BackupsWorker.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -393,7 +393,7 @@ struct BackupsWorker::BackupStarter
393393

394394
/// The "internal" option can only be used by a query that was initiated by another query (e.g., ON CLUSTER query).
395395
/// It should not be allowed for an initial query explicitly specified by a user.
396-
if (is_internal_backup && (query_context->getClientInfo().query_kind == ClientInfo::QueryKind::INITIAL_QUERY))
396+
if (is_internal_backup && !query_context->isDDLOrOnClusterInternal())
397397
throw Exception(ErrorCodes::ACCESS_DENIED, "Setting 'internal' cannot be set explicitly");
398398

399399
on_cluster = !backup_query->cluster.empty() || is_internal_backup;
@@ -846,7 +846,7 @@ struct BackupsWorker::RestoreStarter
846846

847847
/// The "internal" option can only be used by a query that was initiated by another query (e.g., ON CLUSTER query).
848848
/// It should not be allowed for an initial query explicitly specified by a user.
849-
if (is_internal_restore && (query_context->getClientInfo().query_kind == ClientInfo::QueryKind::INITIAL_QUERY))
849+
if (is_internal_restore && !query_context->isDDLOrOnClusterInternal())
850850
throw Exception(ErrorCodes::ACCESS_DENIED, "Setting 'internal' cannot be set explicitly");
851851

852852
/// RESTORE is a write operation, it should be forbidden in strict readonly mode (readonly=1).

src/Databases/DatabaseReplicated.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1276,7 +1276,7 @@ BlockIO DatabaseReplicated::tryEnqueueReplicatedDDL(const ASTPtr & query, Contex
12761276
if (is_readonly)
12771277
throw Exception(ErrorCodes::NO_ZOOKEEPER, "Database is in readonly mode, because it cannot connect to ZooKeeper");
12781278

1279-
if (!flags.internal && (query_context->getClientInfo().query_kind != ClientInfo::QueryKind::INITIAL_QUERY))
1279+
if (!flags.internal && query_context->isDDLOrOnClusterInternal())
12801280
throw Exception(ErrorCodes::INCORRECT_QUERY, "It's not initial query. ON CLUSTER is not allowed for Replicated database.");
12811281

12821282
checkQueryValid(query, query_context);
@@ -1423,7 +1423,7 @@ void DatabaseReplicated::recoverLostReplica(const ZooKeeperPtr & current_zookeep
14231423
{
14241424
auto query_context = Context::createCopy(getContext());
14251425
query_context->makeQueryContext();
1426-
query_context->setQueryKind(ClientInfo::QueryKind::SECONDARY_QUERY);
1426+
query_context->setDDLOrOnClusterInternal(true);
14271427
query_context->setQueryKindReplicatedDatabaseInternal();
14281428
query_context->setCurrentDatabase(getDatabaseName());
14291429
query_context->setCurrentQueryId("");

src/Interpreters/ClientInfo.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ class ClientInfo
5353
{
5454
NO_QUERY = 0, /// Uninitialized object.
5555
INITIAL_QUERY = 1,
56-
SECONDARY_QUERY = 2, /// Query that was initiated by another query for distributed or ON CLUSTER query execution.
56+
SECONDARY_QUERY = 2, /// Query that was initiated by another query for distributed query execution.
5757
};
5858

5959
ClientInfo();

src/Interpreters/Context.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1150,6 +1150,7 @@ ContextData::ContextData(const ContextData &o) :
11501150
global_context(o.global_context),
11511151
buffer_context(o.buffer_context),
11521152
is_internal_query(o.is_internal_query),
1153+
is_ddl_or_on_cluster_internal(o.is_ddl_or_on_cluster_internal),
11531154
is_view_inner_query(o.is_view_inner_query),
11541155
positional_arguments_already_resolved(o.positional_arguments_already_resolved),
11551156
temp_data_on_disk(o.temp_data_on_disk),

src/Interpreters/Context.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -513,6 +513,11 @@ class ContextData
513513

514514
/// A flag, used to distinguish between user query and internal query to a database engine (MaterializedPostgreSQL).
515515
bool is_internal_query = false;
516+
/// Set for queries created internally by the server for DDL replication (ON CLUSTER, DatabaseReplicated)
517+
/// and internal backup coordination.
518+
/// Unlike query_kind == SECONDARY_QUERY (which comes from the client and can be spoofed),
519+
/// this flag can only be set server-side and is safe to use for security-sensitive checks.
520+
bool is_ddl_or_on_cluster_internal = false;
516521
/// True when this context belongs to the inner query of an expanded view.
517522
/// Positional arguments inside views must be resolved even on remote/secondary nodes where
518523
/// enable_positional_arguments would otherwise be skipped (views are expanded on remote nodes,
@@ -1448,6 +1453,9 @@ class Context: public ContextData, public std::enable_shared_from_this<Context>
14481453
bool isInternalQuery() const { return is_internal_query; }
14491454
void setInternalQuery(bool internal) { is_internal_query = internal; }
14501455

1456+
bool isDDLOrOnClusterInternal() const { return is_ddl_or_on_cluster_internal; }
1457+
void setDDLOrOnClusterInternal(bool value) { is_ddl_or_on_cluster_internal = value; }
1458+
14511459
bool isViewInnerQuery() const { return is_view_inner_query; }
14521460
void setIsViewInnerQuery(bool value) { is_view_inner_query = value; }
14531461

src/Interpreters/DDLTask.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,7 @@ ContextMutablePtr DDLTaskBase::makeQueryContext(ContextPtr from_context, const Z
262262
auto query_context = Context::createCopy(from_context);
263263
query_context->makeQueryContext();
264264
query_context->setCurrentQueryId(""); // generate random query_id
265-
query_context->setQueryKind(ClientInfo::QueryKind::SECONDARY_QUERY);
265+
query_context->setDDLOrOnClusterInternal(true);
266266
if (entry.settings)
267267
query_context->applySettingsChanges(*entry.settings);
268268
return query_context;
@@ -598,7 +598,7 @@ void DatabaseReplicatedTask::parseQueryFromEntry(ContextPtr context)
598598
ContextMutablePtr DatabaseReplicatedTask::makeQueryContext(ContextPtr from_context, const ZooKeeperPtr & zookeeper)
599599
{
600600
auto query_context = DDLTaskBase::makeQueryContext(from_context, zookeeper);
601-
query_context->setQueryKind(ClientInfo::QueryKind::SECONDARY_QUERY);
601+
query_context->setDDLOrOnClusterInternal(true);
602602
query_context->setQueryKindReplicatedDatabaseInternal();
603603
query_context->setCurrentDatabase(database->getDatabaseName());
604604

src/Interpreters/InterpreterCreateQuery.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -296,7 +296,7 @@ BlockIO InterpreterCreateQuery::createDatabase(ASTCreateQuery & create)
296296
}
297297
else
298298
{
299-
bool is_on_cluster = getContext()->getClientInfo().query_kind == ClientInfo::QueryKind::SECONDARY_QUERY;
299+
bool is_on_cluster = getContext()->isDDLOrOnClusterInternal();
300300
if (create.uuid != UUIDHelpers::Nil && !is_on_cluster && !internal)
301301
throw Exception(ErrorCodes::INCORRECT_QUERY, "Ordinary database engine does not support UUID");
302302

@@ -1393,7 +1393,7 @@ void InterpreterCreateQuery::assertOrSetUUID(ASTCreateQuery & create, const Data
13931393
const auto * kind_upper = create.is_dictionary ? "DICTIONARY" : "TABLE";
13941394
bool is_replicated_database_internal = database->getEngineName() == "Replicated" && getContext()->getClientInfo().is_replicated_database_internal;
13951395
bool from_path = create.attach_from_path.has_value();
1396-
bool is_on_cluster = getContext()->getClientInfo().query_kind == ClientInfo::QueryKind::SECONDARY_QUERY;
1396+
bool is_on_cluster = getContext()->isDDLOrOnClusterInternal();
13971397

13981398
if (database->getEngineName() == "Replicated" && create.uuid != UUIDHelpers::Nil && !is_replicated_database_internal && !internal && !is_on_cluster && !create.attach)
13991399
{
@@ -1598,7 +1598,7 @@ BlockIO InterpreterCreateQuery::createTable(ASTCreateQuery & create)
15981598
fs::path user_files = fs::path(getContext()->getUserFilesPath()).lexically_normal();
15991599
fs::path root_path = fs::path(getContext()->getPath()).lexically_normal();
16001600

1601-
if (getContext()->getClientInfo().query_kind == ClientInfo::QueryKind::INITIAL_QUERY)
1601+
if (!getContext()->isDDLOrOnClusterInternal())
16021602
{
16031603
fs::path data_path = fs::path(*create.attach_from_path).lexically_normal();
16041604
if (data_path.is_relative())
@@ -1618,7 +1618,7 @@ BlockIO InterpreterCreateQuery::createTable(ASTCreateQuery & create)
16181618
"Data directory {} must be inside {} to attach it", String(data_path), String(user_files));
16191619
}
16201620
}
1621-
else if (create.attach && !create.attach_short_syntax && getContext()->getClientInfo().query_kind != ClientInfo::QueryKind::SECONDARY_QUERY)
1621+
else if (create.attach && !create.attach_short_syntax && !getContext()->isDDLOrOnClusterInternal())
16221622
{
16231623
auto log = getLogger("InterpreterCreateQuery");
16241624
LOG_WARNING(log, "ATTACH TABLE query with full table definition is not recommended: "
@@ -1922,9 +1922,9 @@ bool InterpreterCreateQuery::doCreateTable(ASTCreateQuery & create,
19221922
/// Before actually creating the table, check if it will lead to cyclic dependencies.
19231923
checkTableCanBeAddedWithNoCyclicDependencies(create, query_ptr, getContext());
19241924

1925-
/// Initial queries in Replicated database at this point have query_kind = ClientInfo::QueryKind::SECONNDARY_QUERY,
1925+
/// Initial queries in Replicated database at this point have is_ddl_or_on_cluster_internal = true,
19261926
/// so we need to check whether the query is initial through getZooKeeperMetadataTransaction()->isInitialQuery()
1927-
bool is_initial_query = getContext()->getClientInfo().query_kind == ClientInfo::QueryKind::INITIAL_QUERY ||
1927+
bool is_initial_query = !getContext()->isDDLOrOnClusterInternal() ||
19281928
(getContext()->getZooKeeperMetadataTransaction() && getContext()->getZooKeeperMetadataTransaction()->isInitialQuery());
19291929
bool is_predefined_database = DatabaseCatalog::isPredefinedDatabase(create.getDatabase());
19301930
if (!internal && is_initial_query && !is_predefined_database)

src/Interpreters/InterpreterDropQuery.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ BlockIO InterpreterDropQuery::executeToTableImpl(const ContextPtr & context_, AS
171171
"Table {} is not a Dictionary",
172172
table_id.getNameForLogs());
173173

174-
bool secondary_query = getContext()->getClientInfo().query_kind == ClientInfo::QueryKind::SECONDARY_QUERY;
174+
bool secondary_query = getContext()->isDDLOrOnClusterInternal();
175175
if (!secondary_query && settings[Setting::ignore_drop_queries_probability] != 0 && ast_drop_query.kind == ASTDropQuery::Kind::Drop
176176
&& std::uniform_real_distribution<>(0.0, 1.0)(thread_local_rng) <= settings[Setting::ignore_drop_queries_probability])
177177
{
@@ -718,7 +718,7 @@ void InterpreterDropQuery::executeDropQuery(ASTDropQuery::Kind kind, ContextPtr
718718

719719
if (ignore_sync_setting)
720720
drop_context->setSetting("database_atomic_wait_for_drop_and_detach_synchronously", false);
721-
drop_context->setQueryKind(ClientInfo::QueryKind::SECONDARY_QUERY);
721+
drop_context->setDDLOrOnClusterInternal(true);
722722
if (auto txn = current_context->getZooKeeperMetadataTransaction())
723723
{
724724
/// For Replicated database

src/Storages/Kafka/StorageKafkaUtils.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -253,8 +253,8 @@ void registerStorageKafka(StorageFactory & factory)
253253
throw Exception(
254254
ErrorCodes::BAD_ARGUMENTS, "Either specify both zookeeper path and replica name or none of them");
255255

256-
const auto is_on_cluster = args.getLocalContext()->getClientInfo().query_kind == ClientInfo::QueryKind::SECONDARY_QUERY;
257-
const auto is_replicated_database = args.getLocalContext()->getClientInfo().query_kind == ClientInfo::QueryKind::SECONDARY_QUERY
256+
const auto is_on_cluster = args.getLocalContext()->isDDLOrOnClusterInternal();
257+
const auto is_replicated_database = args.getLocalContext()->isDDLOrOnClusterInternal()
258258
&& DatabaseCatalog::instance().getDatabase(args.table_id.database_name)->getEngineName() == "Replicated";
259259

260260
// UUID macro is only allowed:

src/Storages/MergeTree/registerStorageMergeTree.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,7 @@ static TableZnodeInfo extractZooKeeperPathAndReplicaNameFromEngineArgs(
244244

245245
if (has_valid_arguments)
246246
{
247-
bool is_replicated_database = local_context->getClientInfo().query_kind == ClientInfo::QueryKind::SECONDARY_QUERY &&
247+
bool is_replicated_database = local_context->isDDLOrOnClusterInternal() &&
248248
DatabaseCatalog::instance().getDatabase(table_id.database_name)->getEngineName() == "Replicated";
249249

250250

0 commit comments

Comments
 (0)