diff --git a/src/Storages/StorageDistributed.cpp b/src/Storages/StorageDistributed.cpp index bff01204aa34..a7cae667adee 100644 --- a/src/Storages/StorageDistributed.cpp +++ b/src/Storages/StorageDistributed.cpp @@ -3003,10 +3003,10 @@ void registerStorageHybrid(StorageFactory & factory) // Normalize arguments (evaluate `currentDatabase()`, expand named collections, etc.). // TableFunctionFactory::get mutates the AST in-place inside TableFunctionRemote::parseArguments. - ASTPtr normalized_table_function_ast = table_function_ast->clone(); + replaceCurrentDatabaseFunction(engine_args[i], local_context); + ASTPtr normalized_table_function_ast = engine_args[i]->clone(); auto additional_table_function = TableFunctionFactory::instance().get(normalized_table_function_ast, local_context); ColumnsDescription segment_columns = additional_table_function->getActualTableStructure(local_context, true); - replaceCurrentDatabaseFunction(normalized_table_function_ast, local_context); validate_segment_schema(segment_columns, normalized_table_function_ast->formatForLogging()); diff --git a/tests/queries/0_stateless/03645_hybrid_watermarks.reference b/tests/queries/0_stateless/03645_hybrid_watermarks.reference index 144780c0d6a4..21cc7180ba34 100644 --- a/tests/queries/0_stateless/03645_hybrid_watermarks.reference +++ b/tests/queries/0_stateless/03645_hybrid_watermarks.reference @@ -1,6 +1,6 @@ --- Test 1: CREATE with watermarks --- Test 2: SHOW CREATE TABLE -CREATE TABLE default.t\n(\n `ts` DateTime,\n `value` UInt64\n)\nENGINE = Hybrid(remote(\'localhost:9000\', \'default\', \'local_hot\'), ts > hybridParam(\'hybrid_watermark_hot\', \'DateTime\'), remote(\'localhost:9000\', currentDatabase(), \'local_cold\'), ts <= hybridParam(\'hybrid_watermark_hot\', \'DateTime\'))\nSETTINGS hybrid_watermark_hot = \'2025-09-01\' +CREATE TABLE default.t\n(\n `ts` DateTime,\n `value` UInt64\n)\nENGINE = Hybrid(remote(\'localhost:9000\', \'default\', \'local_hot\'), ts > hybridParam(\'hybrid_watermark_hot\', \'DateTime\'), remote(\'localhost:9000\', \'default\', \'local_cold\'), ts <= hybridParam(\'hybrid_watermark_hot\', \'DateTime\'))\nSETTINGS hybrid_watermark_hot = \'2025-09-01\' --- Test 3: First query after CREATE 1 1 @@ -8,25 +8,25 @@ CREATE TABLE default.t\n(\n `ts` DateTime,\n `value` UInt64\n)\nENGINE = H --- Test 5: Query with updated boundary 1 --- Test 6: SHOW CREATE after ALTER -CREATE TABLE default.t\n(\n `ts` DateTime,\n `value` UInt64\n)\nENGINE = Hybrid(remote(\'localhost:9000\', \'default\', \'local_hot\'), ts > hybridParam(\'hybrid_watermark_hot\', \'DateTime\'), remote(\'localhost:9000\', currentDatabase(), \'local_cold\'), ts <= hybridParam(\'hybrid_watermark_hot\', \'DateTime\'))\nSETTINGS hybrid_watermark_hot = \'2025-10-01\' +CREATE TABLE default.t\n(\n `ts` DateTime,\n `value` UInt64\n)\nENGINE = Hybrid(remote(\'localhost:9000\', \'default\', \'local_hot\'), ts > hybridParam(\'hybrid_watermark_hot\', \'DateTime\'), remote(\'localhost:9000\', \'default\', \'local_cold\'), ts <= hybridParam(\'hybrid_watermark_hot\', \'DateTime\'))\nSETTINGS hybrid_watermark_hot = \'2025-10-01\' --- Test 7: DETACH/ATTACH persistence -CREATE TABLE default.t\n(\n `ts` DateTime,\n `value` UInt64\n)\nENGINE = Hybrid(remote(\'localhost:9000\', \'default\', \'local_hot\'), ts > hybridParam(\'hybrid_watermark_hot\', \'DateTime\'), remote(\'localhost:9000\', currentDatabase(), \'local_cold\'), ts <= hybridParam(\'hybrid_watermark_hot\', \'DateTime\'))\nSETTINGS hybrid_watermark_hot = \'2025-10-01\' +CREATE TABLE default.t\n(\n `ts` DateTime,\n `value` UInt64\n)\nENGINE = Hybrid(remote(\'localhost:9000\', \'default\', \'local_hot\'), ts > hybridParam(\'hybrid_watermark_hot\', \'DateTime\'), remote(\'localhost:9000\', \'default\', \'local_cold\'), ts <= hybridParam(\'hybrid_watermark_hot\', \'DateTime\'))\nSETTINGS hybrid_watermark_hot = \'2025-10-01\' --- Test 8: Three segments, two watermarks -CREATE TABLE default.t3\n(\n `ts` DateTime,\n `value` UInt64\n)\nENGINE = Hybrid(remote(\'localhost:9000\', \'default\', \'local_hot\'), ts > hybridParam(\'hybrid_watermark_hot\', \'DateTime\'), remote(\'localhost:9000\', currentDatabase(), \'local_warm\'), (ts <= hybridParam(\'hybrid_watermark_hot\', \'DateTime\')) AND (ts > hybridParam(\'hybrid_watermark_cold\', \'DateTime\')), remote(\'localhost:9000\', currentDatabase(), \'local_cold\'), ts <= hybridParam(\'hybrid_watermark_cold\', \'DateTime\'))\nSETTINGS hybrid_watermark_cold = \'2025-07-01\', hybrid_watermark_hot = \'2025-10-01\' +CREATE TABLE default.t3\n(\n `ts` DateTime,\n `value` UInt64\n)\nENGINE = Hybrid(remote(\'localhost:9000\', \'default\', \'local_hot\'), ts > hybridParam(\'hybrid_watermark_hot\', \'DateTime\'), remote(\'localhost:9000\', \'default\', \'local_warm\'), (ts <= hybridParam(\'hybrid_watermark_hot\', \'DateTime\')) AND (ts > hybridParam(\'hybrid_watermark_cold\', \'DateTime\')), remote(\'localhost:9000\', \'default\', \'local_cold\'), ts <= hybridParam(\'hybrid_watermark_cold\', \'DateTime\'))\nSETTINGS hybrid_watermark_cold = \'2025-07-01\', hybrid_watermark_hot = \'2025-10-01\' --- Test 9: Reject non-watermark parameter --- Test 10: Missing watermark SETTINGS rejected at CREATE --- Test 11: Invalid typed value --- Test 12: Reject non-watermark MODIFY SETTING --- Test 13: Reject RESET SETTING on Hybrid --- Test 14: Alter one preserves the other -CREATE TABLE default.t3\n(\n `ts` DateTime,\n `value` UInt64\n)\nENGINE = Hybrid(remote(\'localhost:9000\', \'default\', \'local_hot\'), ts > hybridParam(\'hybrid_watermark_hot\', \'DateTime\'), remote(\'localhost:9000\', currentDatabase(), \'local_warm\'), (ts <= hybridParam(\'hybrid_watermark_hot\', \'DateTime\')) AND (ts > hybridParam(\'hybrid_watermark_cold\', \'DateTime\')), remote(\'localhost:9000\', currentDatabase(), \'local_cold\'), ts <= hybridParam(\'hybrid_watermark_cold\', \'DateTime\'))\nSETTINGS hybrid_watermark_cold = \'2025-08-01\', hybrid_watermark_hot = \'2025-12-01\' +CREATE TABLE default.t3\n(\n `ts` DateTime,\n `value` UInt64\n)\nENGINE = Hybrid(remote(\'localhost:9000\', \'default\', \'local_hot\'), ts > hybridParam(\'hybrid_watermark_hot\', \'DateTime\'), remote(\'localhost:9000\', \'default\', \'local_warm\'), (ts <= hybridParam(\'hybrid_watermark_hot\', \'DateTime\')) AND (ts > hybridParam(\'hybrid_watermark_cold\', \'DateTime\')), remote(\'localhost:9000\', \'default\', \'local_cold\'), ts <= hybridParam(\'hybrid_watermark_cold\', \'DateTime\'))\nSETTINGS hybrid_watermark_cold = \'2025-08-01\', hybrid_watermark_hot = \'2025-12-01\' 1 --- Test 15: Reject DistributedSettings at CREATE --- Test 16: Plain Distributed unaffected --- Test 17: Value via SETTINGS 1 1 -CREATE TABLE default.t_settings_only\n(\n `ts` DateTime,\n `value` UInt64\n)\nENGINE = Hybrid(remote(\'localhost:9000\', \'default\', \'local_hot\'), ts > hybridParam(\'hybrid_watermark_hot\', \'DateTime\'), remote(\'localhost:9000\', currentDatabase(), \'local_cold\'), ts <= hybridParam(\'hybrid_watermark_hot\', \'DateTime\'))\nSETTINGS hybrid_watermark_hot = \'2025-09-01\' +CREATE TABLE default.t_settings_only\n(\n `ts` DateTime,\n `value` UInt64\n)\nENGINE = Hybrid(remote(\'localhost:9000\', \'default\', \'local_hot\'), ts > hybridParam(\'hybrid_watermark_hot\', \'DateTime\'), remote(\'localhost:9000\', \'default\', \'local_cold\'), ts <= hybridParam(\'hybrid_watermark_hot\', \'DateTime\'))\nSETTINGS hybrid_watermark_hot = \'2025-09-01\' --- Test 18: Conflicting types rejected --- Test 19: Invalid SETTINGS value rejected at CREATE --- Test 20: Typo in CREATE SETTINGS rejected diff --git a/tests/queries/0_stateless/04302_hybrid_current_database_reattach.reference b/tests/queries/0_stateless/04302_hybrid_current_database_reattach.reference new file mode 100644 index 000000000000..7290ba859f4a --- /dev/null +++ b/tests/queries/0_stateless/04302_hybrid_current_database_reattach.reference @@ -0,0 +1,2 @@ +4 +4 diff --git a/tests/queries/0_stateless/04302_hybrid_current_database_reattach.sql b/tests/queries/0_stateless/04302_hybrid_current_database_reattach.sql new file mode 100644 index 000000000000..8ed53ef63ebb --- /dev/null +++ b/tests/queries/0_stateless/04302_hybrid_current_database_reattach.sql @@ -0,0 +1,38 @@ +-- Reproduce the Hybrid currentDatabase() metadata bug without a server restart. +-- Detaching the table and re-attaching it while a different database is current +-- mimics the missing session-database context that startup ATTACH has. Before the +-- fix the stored metadata keeps currentDatabase(), which then resolves to the wrong +-- database and the segment fails to attach with UNKNOWN_TABLE. + +SET allow_experimental_hybrid_table = 1; + +CREATE TABLE {CLICKHOUSE_DATABASE:Identifier}.local_hot (ts DateTime, value UInt64) ENGINE = MergeTree ORDER BY ts; +CREATE TABLE {CLICKHOUSE_DATABASE:Identifier}.local_cold (ts DateTime, value UInt64) ENGINE = MergeTree ORDER BY ts; +INSERT INTO {CLICKHOUSE_DATABASE:Identifier}.local_hot VALUES ('2025-10-15', 1), ('2025-11-01', 2); +INSERT INTO {CLICKHOUSE_DATABASE:Identifier}.local_cold VALUES ('2025-08-01', 3), ('2025-06-15', 4); + +-- Create with the test database as current so currentDatabase() resolves to it. +USE {CLICKHOUSE_DATABASE:Identifier}; +CREATE TABLE {CLICKHOUSE_DATABASE:Identifier}.hybrid_t (ts DateTime, value UInt64) +ENGINE = Hybrid( + remote('localhost:9000', {CLICKHOUSE_DATABASE:String}, 'local_hot'), + ts > hybridParam('hybrid_watermark_hot', 'DateTime'), + remote('localhost:9000', currentDatabase(), 'local_cold'), + ts <= hybridParam('hybrid_watermark_hot', 'DateTime') +) +SETTINGS hybrid_watermark_hot = '2025-09-01'; + +SELECT count() FROM {CLICKHOUSE_DATABASE:Identifier}.hybrid_t; + +-- Detach, switch the current database, then re-attach. currentDatabase() in the +-- stored metadata now resolves against the other database, whose local_cold does +-- not exist. With the fix the metadata holds the resolved name, so this succeeds. +DETACH TABLE {CLICKHOUSE_DATABASE:Identifier}.hybrid_t; +CREATE DATABASE IF NOT EXISTS {CLICKHOUSE_DATABASE_1:Identifier}; +USE {CLICKHOUSE_DATABASE_1:Identifier}; +ATTACH TABLE {CLICKHOUSE_DATABASE:Identifier}.hybrid_t; + +SELECT count() FROM {CLICKHOUSE_DATABASE:Identifier}.hybrid_t; + +USE {CLICKHOUSE_DATABASE:Identifier}; +DROP DATABASE {CLICKHOUSE_DATABASE_1:Identifier};