Skip to content

Commit 15ad477

Browse files
Merge pull request ClickHouse#80037 from ClickHouse/repro-union-matview-failure
Fix bug where materialized views with UNIONs don't work on new replicas
2 parents 7cc6324 + b1d8df9 commit 15ad477

File tree

3 files changed

+92
-1
lines changed

3 files changed

+92
-1
lines changed

src/Databases/DatabaseReplicated.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include <Interpreters/DatabaseCatalog.h>
2525
#include <Interpreters/InterpreterCreateQuery.h>
2626
#include <Interpreters/InterpreterSetQuery.h>
27+
#include <Interpreters/NormalizeSelectWithUnionQueryVisitor.h>
2728
#include <Interpreters/ReplicatedDatabaseQueryStatusSource.h>
2829
#include <Interpreters/evaluateConstantExpression.h>
2930
#include <Interpreters/executeDDLQueryOnCluster.h>
@@ -66,6 +67,7 @@ namespace Setting
6667
extern const SettingsDistributedDDLOutputMode distributed_ddl_output_mode;
6768
extern const SettingsInt64 distributed_ddl_task_timeout;
6869
extern const SettingsBool throw_on_unsupported_query_inside_transaction;
70+
extern const SettingsSetOperationMode union_default_mode;
6971
}
7072

7173
namespace ServerSetting
@@ -1463,8 +1465,11 @@ void DatabaseReplicated::recoverLostReplica(const ZooKeeperPtr & current_zookeep
14631465
}
14641466

14651467
auto query_ast = parseQueryFromMetadataInZooKeeper(table_name, create_query_string);
1466-
14671468
auto create_query_context = make_query_context();
1469+
1470+
NormalizeSelectWithUnionQueryVisitor::Data data{create_query_context->getSettingsRef()[Setting::union_default_mode]};
1471+
NormalizeSelectWithUnionQueryVisitor{data}.visit(query_ast);
1472+
14681473
/// Check larger comment in DatabaseOnDisk::createTableFromAST
14691474
/// TL;DR applySettingsFromQuery will move the settings from engine to query level
14701475
/// making it possible to overcome a backward incompatible change.

tests/integration/test_matview_union_replicated/__init__.py

Whitespace-only changes.
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
import pytest
2+
from helpers.cluster import ClickHouseCluster
3+
from helpers.test_tools import assert_eq_with_retry
4+
5+
cluster = ClickHouseCluster(__file__)
6+
7+
# Create two nodes - one main node and one replica
8+
node1 = cluster.add_instance("node1", with_zookeeper=True)
9+
node2 = cluster.add_instance("node2", with_zookeeper=True)
10+
11+
@pytest.fixture(scope="module")
12+
def started_cluster():
13+
try:
14+
cluster.start()
15+
yield cluster
16+
finally:
17+
cluster.shutdown()
18+
19+
def test_matview_union_replicated(started_cluster):
20+
21+
# Create replicated database, source and target tables and matview
22+
node1.query("DROP DATABASE IF EXISTS union_test_replicated SYNC")
23+
node1.query("CREATE DATABASE union_test_replicated ENGINE=Replicated('/test/union_replica' , 'shard1', 'replica' || '1');")
24+
25+
node1.query("""
26+
CREATE TABLE union_test_replicated.source_1
27+
(
28+
timestamp DateTime,
29+
value Float64
30+
)
31+
ENGINE = ReplicatedMergeTree
32+
ORDER BY timestamp
33+
""")
34+
35+
node1.query("""
36+
CREATE TABLE union_test_replicated.source_2
37+
(
38+
timestamp DateTime,
39+
value Float64
40+
)
41+
ENGINE = ReplicatedMergeTree
42+
ORDER BY timestamp
43+
""")
44+
45+
node1.query("""
46+
CREATE TABLE union_test_replicated.target
47+
(
48+
timestamp DateTime,
49+
value Float64
50+
)
51+
ENGINE = ReplicatedMergeTree
52+
ORDER BY timestamp
53+
""")
54+
55+
node1.query("""
56+
CREATE MATERIALIZED VIEW union_test_replicated.mv_test TO union_test_replicated.target AS
57+
WITH source_data AS
58+
(
59+
SELECT timestamp, value FROM union_test_replicated.source_1
60+
UNION ALL
61+
SELECT timestamp, value FROM union_test_replicated.source_2
62+
)
63+
SELECT timestamp, value FROM source_data
64+
""")
65+
66+
# Verify INSERT works on Node #1
67+
node1.query("INSERT INTO union_test_replicated.source_1 VALUES (now(), 1)")
68+
69+
# Attach replica on second node
70+
node2.query("DROP DATABASE IF EXISTS union_test_replicated SYNC")
71+
node2.query("CREATE DATABASE union_test_replicated ENGINE=Replicated('/test/union_replica' , 'shard1', 'replica' || '2');")
72+
node2.query("SYSTEM SYNC DATABASE REPLICA union_test_replicated")
73+
74+
# Verify the table structure on replica
75+
assert_eq_with_retry(
76+
node2,
77+
"DESCRIBE TABLE union_test_replicated.source_1",
78+
"timestamp\tDateTime\t\t\t\t\nvalue\tFloat64\t\t\t\t\n"
79+
)
80+
81+
# Run INSERT on replica
82+
node2.query("INSERT INTO union_test_replicated.source_1 VALUES (now(), 1)")
83+
84+
# Clean up
85+
node1.query("DROP DATABASE IF EXISTS union_test_replicated SYNC")
86+
node2.query("DROP DATABASE IF EXISTS union_test_replicated SYNC")

0 commit comments

Comments
 (0)