-
Notifications
You must be signed in to change notification settings - Fork 198
Expand file tree
/
Copy pathvalidation.go
More file actions
105 lines (95 loc) · 3.6 KB
/
Copy pathvalidation.go
File metadata and controls
105 lines (95 loc) · 3.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
package clickhouse
import (
"context"
"errors"
"fmt"
"log/slog"
"slices"
"strings"
"github.com/ClickHouse/clickhouse-go/v2"
"go.temporal.io/sdk/log"
)
var acceptableTableEngines = []string{"ReplacingMergeTree", "MergeTree", "ReplicatedReplacingMergeTree", "ReplicatedMergeTree", "Null"}
func CheckIfClickHouseCloudHasSharedMergeTreeEnabled(ctx context.Context, logger log.Logger,
conn clickhouse.Conn,
) error {
// this is to indicate ClickHouse Cloud service is now creating tables with Shared* by default
var cloudModeEngine bool
if err := QueryRow(ctx, logger, conn,
"SELECT value='2' AND changed='1' AND readonly='1' FROM system.settings WHERE name = 'cloud_mode_engine'").
Scan(&cloudModeEngine); err != nil {
return fmt.Errorf("failed to validate cloud_mode_engine setting: %w", err)
}
if !cloudModeEngine {
return errors.New("ClickHouse service is not migrated to use SharedMergeTree tables, please contact support")
}
return nil
}
func CheckIfTablesEmptyAndEngine(ctx context.Context, logger log.Logger, conn clickhouse.Conn,
tables []string, initialSnapshotEnabled bool, checkForCloudSMT bool,
) error {
queryInput := make([]any, 0, len(tables))
for _, table := range tables {
queryInput = append(queryInput, table)
}
rows, err := Query(ctx, logger, conn,
fmt.Sprintf("SELECT name,engine,total_rows FROM system.tables WHERE database=currentDatabase() AND name IN (%s)",
strings.Join(slices.Repeat([]string{"?"}, len(tables)), ",")), queryInput...)
if err != nil {
return fmt.Errorf("failed to get information for destination tables: %w", err)
}
defer rows.Close()
for rows.Next() {
var tableName, engine string
var totalRows uint64
if err := rows.Scan(&tableName, &engine, &totalRows); err != nil {
return fmt.Errorf("failed to scan information for tables: %w", err)
}
if totalRows != 0 && initialSnapshotEnabled {
return fmt.Errorf("table %s exists and is not empty", tableName)
}
if !slices.Contains(acceptableTableEngines, strings.TrimPrefix(engine, "Shared")) {
logger.Warn("[clickhouse] table engine not explicitly supported",
slog.String("table", tableName), slog.String("engine", engine))
}
if checkForCloudSMT && !strings.HasPrefix(engine, "Shared") {
return fmt.Errorf("table %s exists and does not use SharedMergeTree engine", tableName)
}
}
if err := rows.Err(); err != nil {
return fmt.Errorf("failed to read rows: %w", err)
}
return nil
}
type ClickHouseColumn struct {
Name string
Type string
}
func GetTableColumnsMapping(ctx context.Context, logger log.Logger, conn clickhouse.Conn,
tables []string,
) (map[string][]ClickHouseColumn, error) {
tableColumnsMapping := make(map[string][]ClickHouseColumn, len(tables))
queryInput := make([]any, 0, len(tables))
for _, table := range tables {
queryInput = append(queryInput, table)
}
rows, err := Query(ctx, logger, conn,
fmt.Sprintf("SELECT name,type,table FROM system.columns WHERE database=currentDatabase() AND table IN (%s)",
strings.Join(slices.Repeat([]string{"?"}, len(tables)), ",")), queryInput...)
if err != nil {
return nil, fmt.Errorf("failed to get columns for destination tables: %w", err)
}
defer rows.Close()
for rows.Next() {
var tableName string
var clickhouseColumn ClickHouseColumn
if err := rows.Scan(&clickhouseColumn.Name, &clickhouseColumn.Type, &tableName); err != nil {
return nil, fmt.Errorf("failed to scan columns for tables: %w", err)
}
tableColumnsMapping[tableName] = append(tableColumnsMapping[tableName], clickhouseColumn)
}
if err := rows.Err(); err != nil {
return nil, fmt.Errorf("failed to read rows: %w", err)
}
return tableColumnsMapping, nil
}