diff --git a/pkg/clickhouse/clickhouse.go b/pkg/clickhouse/clickhouse.go index e615a081..6c47a0f7 100644 --- a/pkg/clickhouse/clickhouse.go +++ b/pkg/clickhouse/clickhouse.go @@ -1044,6 +1044,8 @@ var attachViewRefreshRe = regexp.MustCompile(`(?im)^(ATTACH[\s\w]+VIEW[^(]+)(\s+ var attachViewToClauseRe = regexp.MustCompile(`(?im)^(ATTACH[\s\w]+VIEW[^(]+)(\s+TO\s+.+)`) var attachViewAsWithRe = regexp.MustCompile(`(?im)^(ATTACH[\s\w]+VIEW[^(]+)(\s+AS\s+WITH\s+.+)`) var attachViewRe = regexp.MustCompile(`(?im)^(ATTACH[\s\w]+VIEW[^(]+)(\s+AS\s+.+)`) +var viewStorageRe = regexp.MustCompile(`(?im)^((?:ATTACH|CREATE)[\s\w]+VIEW\s+(?:IF\s+NOT\s+EXISTS\s+)?\S+(?:\s+UUID\s+'[^']+')?)(\s+ENGINE\s*=?\s*.+)`) +var viewColumnsRe = regexp.MustCompile(`(?im)^((?:ATTACH|CREATE)[\s\w]+VIEW\s+(?:IF\s+NOT\s+EXISTS\s+)?\S+(?:\s+UUID\s+'[^']+')?)\s*(\(.+\s+(?:AS|TO)\s+.+)`) var createObjRe = regexp.MustCompile(`(?is)^(CREATE [^(]+)(\(.+)`) var onClusterRe = regexp.MustCompile(`(?im)\s+ON\s+CLUSTER\s+`) var distributedRE = regexp.MustCompile(`(Distributed)\(([^,]+),([^)]+)\)`) @@ -1171,7 +1173,7 @@ func (ch *ClickHouse) CreateTableAsAttach(query string) error { func (ch *ClickHouse) enrichQueryWithOnCluster(query string, onCluster string, version int, databaseEngine string) string { if version > 19000000 && !strings.HasPrefix(databaseEngine, "Replicated") && onCluster != "" && !onClusterRe.MatchString(query) { - tryMatchReList := []*regexp.Regexp{attachViewRefreshRe, attachViewToClauseRe, attachViewAsWithRe, attachViewRe, createViewRefreshRe, createViewToClauseRe, createViewAsWithRe, createViewRe, createObjRe} + tryMatchReList := []*regexp.Regexp{attachViewRefreshRe, attachViewToClauseRe, viewStorageRe, attachViewAsWithRe, attachViewRe, createViewRefreshRe, createViewToClauseRe, createViewAsWithRe, createViewRe, viewColumnsRe, createObjRe} for _, tryMatchRe := range tryMatchReList { if tryMatchRe.MatchString(query) { query = tryMatchRe.ReplaceAllString(query, "$1 ON CLUSTER '"+onCluster+"' $2") diff --git a/pkg/clickhouse/clickhouse_test.go b/pkg/clickhouse/clickhouse_test.go index abcbc954..d6ab1702 100644 --- a/pkg/clickhouse/clickhouse_test.go +++ b/pkg/clickhouse/clickhouse_test.go @@ -148,11 +148,11 @@ func TestEnrichQueryWithOnCluster(t *testing.T) { ExpectedQuery: "CREATE TABLE test ON CLUSTER 'my_cluster' (id UInt64) ENGINE = MergeTree ORDER BY id", }, { - Name: "OnCluster provided, version >= 19000000, CREATE VIEW with TO clause", - Query: "CREATE VIEW test_view TO test_table AS SELECT * FROM test_table", + Name: "OnCluster provided, version >= 19000000, CREATE MATERIALIZED VIEW with TO clause", + Query: "CREATE MATERIALIZED VIEW test_view TO test_table AS SELECT * FROM test_table", OnCluster: "my_cluster", Version: 19000001, - ExpectedQuery: "CREATE VIEW test_view ON CLUSTER 'my_cluster' TO test_table AS SELECT * FROM test_table", + ExpectedQuery: "CREATE MATERIALIZED VIEW test_view ON CLUSTER 'my_cluster' TO test_table AS SELECT * FROM test_table", }, { Name: "OnCluster provided, version >= 19000000, CREATE VIEW with AS SELECT", @@ -162,11 +162,11 @@ func TestEnrichQueryWithOnCluster(t *testing.T) { ExpectedQuery: "CREATE VIEW test_view ON CLUSTER 'my_cluster' AS SELECT * FROM test_table", }, { - Name: "OnCluster provided, version >= 19000000, ATTACH VIEW with TO clause", - Query: "ATTACH VIEW test_view TO test_table AS SELECT * FROM test_table", + Name: "OnCluster provided, version >= 19000000, CREATE MATERIALIZED VIEW with ENGINE clause", + Query: "CREATE MATERIALIZED VIEW test_view ENGINE = AggregatingMergeTree() ORDER BY t AS SELECT * FROM test_table", OnCluster: "my_cluster", Version: 19000001, - ExpectedQuery: "ATTACH VIEW test_view ON CLUSTER 'my_cluster' TO test_table AS SELECT * FROM test_table", + ExpectedQuery: "CREATE MATERIALIZED VIEW test_view ON CLUSTER 'my_cluster' ENGINE = AggregatingMergeTree() ORDER BY t AS SELECT * FROM test_table", }, { Name: "OnCluster provided, version >= 19000000, ATTACH VIEW with AS SELECT", @@ -175,6 +175,55 @@ func TestEnrichQueryWithOnCluster(t *testing.T) { Version: 19000001, ExpectedQuery: "ATTACH VIEW test_view ON CLUSTER 'my_cluster' AS SELECT * FROM test_table", }, + { + Name: "OnCluster provided, version >= 19000000, ATTACH LIVE VIEW with columns", + Query: "ATTACH LIVE VIEW test.daily_sales_live UUID '8190d585-1111-2222-3333-444444444444' (`event_date` UInt32, `sku_id` String, `total_sales` Decimal(38, 2)) AS SELECT event_date FROM test.sales", + OnCluster: "my_cluster", + Version: 19000001, + ExpectedQuery: "ATTACH LIVE VIEW test.daily_sales_live UUID '8190d585-1111-2222-3333-444444444444' ON CLUSTER 'my_cluster' (`event_date` UInt32, `sku_id` String, `total_sales` Decimal(38, 2)) AS SELECT event_date FROM test.sales", + }, + { + Name: "OnCluster provided, version >= 19000000, ATTACH WINDOW VIEW with engine and settings", + Query: "ATTACH WINDOW VIEW test.wv UUID '6b87827c-1111-2222-3333-444444444444' ENGINE AggregatingMergeTree() ORDER BY total SETTINGS index_granularity = 8192 AS SELECT total FROM test.src", + OnCluster: "my_cluster", + Version: 19000001, + ExpectedQuery: "ATTACH WINDOW VIEW test.wv UUID '6b87827c-1111-2222-3333-444444444444' ON CLUSTER 'my_cluster' ENGINE AggregatingMergeTree() ORDER BY total SETTINGS index_granularity = 8192 AS SELECT total FROM test.src", + }, + { + Name: "OnCluster provided, version >= 19000000, CREATE VIEW with columns", + Query: "CREATE VIEW test_view (`id` UInt64) AS SELECT id FROM test_table", + OnCluster: "my_cluster", + Version: 19000001, + ExpectedQuery: "CREATE VIEW test_view ON CLUSTER 'my_cluster' (`id` UInt64) AS SELECT id FROM test_table", + }, + { + Name: "OnCluster provided, version >= 19000000, ATTACH VIEW without columns regression", + Query: "ATTACH VIEW test_view AS SELECT id FROM test_table", + OnCluster: "my_cluster", + Version: 19000001, + ExpectedQuery: "ATTACH VIEW test_view ON CLUSTER 'my_cluster' AS SELECT id FROM test_table", + }, + { + Name: "OnCluster already present leaves query unchanged", + Query: "ATTACH VIEW test_view ON CLUSTER 'my_cluster' AS SELECT * FROM test_table", + OnCluster: "my_cluster", + Version: 19000001, + ExpectedQuery: "ATTACH VIEW test_view ON CLUSTER 'my_cluster' AS SELECT * FROM test_table", + }, + { + Name: "Version before ON CLUSTER support leaves ATTACH LIVE VIEW unchanged", + Query: "ATTACH LIVE VIEW test.daily_sales_live UUID '8190d585-1111-2222-3333-444444444444' (`event_date` UInt32, `sku_id` String, `total_sales` Decimal(38, 2)) AS SELECT event_date FROM test.sales", + OnCluster: "my_cluster", + Version: 18999999, + ExpectedQuery: "ATTACH LIVE VIEW test.daily_sales_live UUID '8190d585-1111-2222-3333-444444444444' (`event_date` UInt32, `sku_id` String, `total_sales` Decimal(38, 2)) AS SELECT event_date FROM test.sales", + }, + { + Name: "Empty OnCluster leaves ATTACH WINDOW VIEW unchanged", + Query: "ATTACH WINDOW VIEW test.wv UUID '6b87827c-1111-2222-3333-444444444444' (`total` Decimal(38, 2), `w_start` DateTime) ENGINE = MergeTree ORDER BY total SETTINGS index_granularity = 8192 AS SELECT total FROM test.src", + OnCluster: "", + Version: 19000001, + ExpectedQuery: "ATTACH WINDOW VIEW test.wv UUID '6b87827c-1111-2222-3333-444444444444' (`total` Decimal(38, 2), `w_start` DateTime) ENGINE = MergeTree ORDER BY total SETTINGS index_granularity = 8192 AS SELECT total FROM test.src", + }, { Name: "OnCluster provided, version >= 19000000, CREATE DICTIONARY", Query: "CREATE DICTIONARY test_dict (id UInt64) PRIMARY KEY id SOURCE(CLICKHOUSE(HOST 'localhost')) LAYOUT(HASHED())",