dbhose-airflow 0.0.2.0__py3-none-any.whl → 0.0.2.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- dbhose_airflow/LOGO +9 -0
- dbhose_airflow/__init__.py +28 -4
- dbhose_airflow/chunk_query.py +14 -0
- dbhose_airflow/ddl/clickhouse.sql +81 -0
- dbhose_airflow/ddl/greenplum.sql +229 -0
- dbhose_airflow/ddl/postgres.sql +209 -0
- dbhose_airflow/dq/clickhouse/empty.sql +1 -0
- dbhose_airflow/dq/clickhouse/future.sql +34 -0
- dbhose_airflow/dq/clickhouse/infinity.sql +34 -0
- dbhose_airflow/dq/clickhouse/nan.sql +34 -0
- dbhose_airflow/dq/clickhouse/sum.sql +72 -0
- dbhose_airflow/dq/clickhouse/total.sql +1 -0
- dbhose_airflow/dq/clickhouse/uniq.sql +1 -0
- dbhose_airflow/dq/greenplum/empty.sql +1 -0
- dbhose_airflow/dq/greenplum/future.sql +55 -0
- dbhose_airflow/dq/greenplum/infinity.sql +60 -0
- dbhose_airflow/dq/greenplum/nan.sql +58 -0
- dbhose_airflow/dq/greenplum/sum.sql +63 -0
- dbhose_airflow/dq/greenplum/total.sql +1 -0
- dbhose_airflow/dq/greenplum/uniq.sql +2 -0
- dbhose_airflow/dq/postgres/empty.sql +1 -0
- dbhose_airflow/dq/postgres/future.sql +55 -0
- dbhose_airflow/dq/postgres/infinity.sql +60 -0
- dbhose_airflow/dq/postgres/nan.sql +58 -0
- dbhose_airflow/dq/postgres/sum.sql +63 -0
- dbhose_airflow/dq/postgres/total.sql +1 -0
- dbhose_airflow/dq/postgres/uniq.sql +2 -0
- dbhose_airflow/move/clickhouse/delete.sql +81 -0
- dbhose_airflow/move/clickhouse/replace.sql +24 -0
- dbhose_airflow/move/greenplum/delete.sql +10 -0
- dbhose_airflow/move/greenplum/replace.sql +60 -0
- dbhose_airflow/move/postgres/delete.sql +10 -0
- dbhose_airflow/move/postgres/replace.sql +60 -0
- dbhose_airflow/move_method.py +1 -0
- {dbhose_airflow-0.0.2.0.dist-info → dbhose_airflow-0.0.2.2.dist-info}/METADATA +3 -3
- dbhose_airflow-0.0.2.2.dist-info/RECORD +43 -0
- {dbhose_airflow-0.0.2.0.dist-info → dbhose_airflow-0.0.2.2.dist-info}/licenses/CHANGELOG.md +14 -0
- dbhose_airflow-0.0.2.0.dist-info/RECORD +0 -11
- {dbhose_airflow-0.0.2.0.dist-info → dbhose_airflow-0.0.2.2.dist-info}/WHEEL +0 -0
- {dbhose_airflow-0.0.2.0.dist-info → dbhose_airflow-0.0.2.2.dist-info}/licenses/README.md +0 -0
- {dbhose_airflow-0.0.2.0.dist-info → dbhose_airflow-0.0.2.2.dist-info}/top_level.txt +0 -0
dbhose_airflow/LOGO
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
|
|
2
|
+
( )
|
|
3
|
+
( ( ) )\ ) ( ( /(
|
|
4
|
+
)\))( ' ( ( ) ( ( /( (()/( ( )\ )\()) (
|
|
5
|
+
((_)()\ ) ))\ )\ ( ( ( ))\ )\()) ( /(_)) )((_) ((_)\ ( ( ))\
|
|
6
|
+
_(())\_)() /((_) (( ) )\ )\ )\ ' /((_) (_))/ )\ (_))_ ((_)_ _((_) )\ )\ /((_)
|
|
7
|
+
\ \((_)/ /(_)) | | ((_) ((_) _((_)) (_)) | |_ ((_) | \ | _ ) | || | ((_) ((_) (_))
|
|
8
|
+
\ \/\/ / / -_) | | / _| / _ \ | ' \() / -_) | _| / _ \ | |) | | _ \ | __ | / _ \ (_-< / -_)
|
|
9
|
+
\_/\_/ \___| |_| \__| \___/ |_|_|_| \___| \__| \___/ |___/ |___/ |_||_| \___/ /__/ \___|
|
dbhose_airflow/__init__.py
CHANGED
|
@@ -14,6 +14,7 @@ from pandas import DataFrame as PDFrame
|
|
|
14
14
|
from polars import DataFrame as PLFrame
|
|
15
15
|
|
|
16
16
|
from .airflow_connect import dbhose_dumper
|
|
17
|
+
from .chunk_query import query_part
|
|
17
18
|
from .dq_check import DQCheck
|
|
18
19
|
from .move_method import MoveMethod
|
|
19
20
|
|
|
@@ -31,7 +32,7 @@ __all__ = (
|
|
|
31
32
|
"dbhose_dumper",
|
|
32
33
|
)
|
|
33
34
|
__author__ = "0xMihalich"
|
|
34
|
-
__version__ = "0.0.2.
|
|
35
|
+
__version__ = "0.0.2.2"
|
|
35
36
|
|
|
36
37
|
|
|
37
38
|
root_path = dirname(__file__)
|
|
@@ -104,7 +105,7 @@ class DBHose:
|
|
|
104
105
|
self.connection_dest = connection_dest
|
|
105
106
|
self.connection_src = connection_src
|
|
106
107
|
self.dq_skip_check = dq_skip_check
|
|
107
|
-
self.filter_by = filter_by
|
|
108
|
+
self.filter_by = ", ".join(filter_by)
|
|
108
109
|
self.drop_temp_table = drop_temp_table
|
|
109
110
|
self.move_method = move_method
|
|
110
111
|
self.custom_move = custom_move
|
|
@@ -333,12 +334,23 @@ class DBHose:
|
|
|
333
334
|
self.logger.error(wrap_frame(error_msg))
|
|
334
335
|
raise ValueError(error_msg)
|
|
335
336
|
|
|
336
|
-
|
|
337
|
+
for query in query_part(self.custom_move):
|
|
338
|
+
self.dumper_dest.cursor.execute(query)
|
|
337
339
|
|
|
338
340
|
if self.dumper_dest.__class__ is not NativeDumper:
|
|
339
341
|
self.dumper_dest.connect.commit()
|
|
340
342
|
|
|
341
343
|
elif self.move_method.have_sql:
|
|
344
|
+
|
|
345
|
+
if (
|
|
346
|
+
self.move_method is MoveMethod.delete
|
|
347
|
+
and self.dumper_dest.__class__ is NativeDumper
|
|
348
|
+
and len(self.filter_by.split(", ")) > 4
|
|
349
|
+
):
|
|
350
|
+
error_msg = "Too many columns in filter_by (> 4)"
|
|
351
|
+
self.logger.error(wrap_frame(error_msg))
|
|
352
|
+
raise ValueError(error_msg)
|
|
353
|
+
|
|
342
354
|
move_query = read_text(
|
|
343
355
|
mv_path.format(self.dumper_dest.dbname, self.move_method.name)
|
|
344
356
|
)
|
|
@@ -357,12 +369,24 @@ class DBHose:
|
|
|
357
369
|
self.logger.error(wrap_frame(error_msg))
|
|
358
370
|
raise ValueError(error_msg)
|
|
359
371
|
|
|
360
|
-
|
|
372
|
+
for query in query_part(move_query):
|
|
373
|
+
self.dumper_dest.cursor.execute(query)
|
|
361
374
|
|
|
362
375
|
if self.dumper_dest.__class__ is not NativeDumper:
|
|
363
376
|
self.dumper_dest.connect.commit()
|
|
364
377
|
|
|
365
378
|
else:
|
|
379
|
+
if self.move_method is MoveMethod.rewrite:
|
|
380
|
+
self.logger.info("Clear table operation start")
|
|
381
|
+
self.dumper_dest.cursor.execute(
|
|
382
|
+
f"truncate table {self.table_dest}"
|
|
383
|
+
)
|
|
384
|
+
|
|
385
|
+
if self.dumper_dest.__class__ is not NativeDumper:
|
|
386
|
+
self.dumper_dest.connect.commit()
|
|
387
|
+
|
|
388
|
+
self.logger.info("Clear table operation done")
|
|
389
|
+
|
|
366
390
|
self.dumper_dest.write_between(self.table_dest, self.table_temp)
|
|
367
391
|
|
|
368
392
|
self.logger.info(wrap_frame(f"Data moved into {self.table_dest}"))
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
from re import split
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
pattern = r";(?=(?:[^']*'[^']*')*[^']*$)"
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def query_part(query: str) -> tuple[str]:
|
|
8
|
+
"""Chunk multiquery to parts."""
|
|
9
|
+
|
|
10
|
+
return (
|
|
11
|
+
part.strip(";").strip()
|
|
12
|
+
for part in split(pattern, query)
|
|
13
|
+
if part.strip(";").strip()
|
|
14
|
+
)
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
WITH
|
|
2
|
+
split_table AS (
|
|
3
|
+
SELECT
|
|
4
|
+
splitByChar('.', '{table}')[1] as db,
|
|
5
|
+
splitByChar('.', '{table}')[2] as tbl
|
|
6
|
+
),
|
|
7
|
+
original_ddl AS (
|
|
8
|
+
SELECT create_table_query
|
|
9
|
+
FROM system.tables
|
|
10
|
+
WHERE database = (SELECT db FROM split_table)
|
|
11
|
+
AND name = (SELECT tbl FROM split_table)
|
|
12
|
+
),
|
|
13
|
+
columns_data AS (
|
|
14
|
+
SELECT
|
|
15
|
+
groupArray(
|
|
16
|
+
tuple(name, type, default_expression, comment)
|
|
17
|
+
) as cols
|
|
18
|
+
FROM (
|
|
19
|
+
SELECT
|
|
20
|
+
name,
|
|
21
|
+
type,
|
|
22
|
+
default_expression,
|
|
23
|
+
comment
|
|
24
|
+
FROM system.columns
|
|
25
|
+
WHERE database = (SELECT db FROM split_table)
|
|
26
|
+
AND table = (SELECT tbl FROM split_table)
|
|
27
|
+
ORDER BY position
|
|
28
|
+
)
|
|
29
|
+
),
|
|
30
|
+
table_info AS (
|
|
31
|
+
SELECT
|
|
32
|
+
partition_key,
|
|
33
|
+
sorting_key,
|
|
34
|
+
primary_key
|
|
35
|
+
FROM system.tables
|
|
36
|
+
WHERE database = (SELECT db FROM split_table)
|
|
37
|
+
AND name = (SELECT tbl FROM split_table)
|
|
38
|
+
),
|
|
39
|
+
order_by_clause AS (
|
|
40
|
+
SELECT
|
|
41
|
+
if((SELECT sorting_key FROM table_info) != '',
|
|
42
|
+
concat('ORDER BY (', (SELECT sorting_key FROM table_info), ')'),
|
|
43
|
+
if((SELECT primary_key FROM table_info) != '',
|
|
44
|
+
concat('ORDER BY (', (SELECT primary_key FROM table_info), ')'),
|
|
45
|
+
'ORDER BY tuple()'
|
|
46
|
+
)
|
|
47
|
+
) as order_by
|
|
48
|
+
)
|
|
49
|
+
SELECT
|
|
50
|
+
(SELECT create_table_query FROM original_ddl) as ddl,
|
|
51
|
+
concat(
|
|
52
|
+
'CREATE TABLE IF NOT EXISTS ',
|
|
53
|
+
(SELECT db FROM split_table),
|
|
54
|
+
'.',
|
|
55
|
+
(SELECT tbl FROM split_table),
|
|
56
|
+
'_temp\n(\n',
|
|
57
|
+
arrayStringConcat(
|
|
58
|
+
arrayMap(
|
|
59
|
+
c -> concat(' ', c.1, ' ', c.2,
|
|
60
|
+
if(c.3 != '', concat(' DEFAULT ', c.3), ''),
|
|
61
|
+
if(c.4 != '', concat(' COMMENT ''', c.4, ''''), '')
|
|
62
|
+
),
|
|
63
|
+
(SELECT cols FROM columns_data)
|
|
64
|
+
),
|
|
65
|
+
',' || '\n'
|
|
66
|
+
),
|
|
67
|
+
'\n)\nENGINE = MergeTree()',
|
|
68
|
+
if((SELECT partition_key FROM table_info) != '',
|
|
69
|
+
concat('\nPARTITION BY ', (SELECT partition_key FROM table_info)),
|
|
70
|
+
''),
|
|
71
|
+
if((SELECT order_by FROM order_by_clause) != '',
|
|
72
|
+
concat('\n', (SELECT order_by FROM order_by_clause)),
|
|
73
|
+
''),
|
|
74
|
+
'\nSETTINGS index_granularity = 8192'
|
|
75
|
+
) as temp_ddl,
|
|
76
|
+
concat(
|
|
77
|
+
(SELECT db FROM split_table),
|
|
78
|
+
'.',
|
|
79
|
+
(SELECT tbl FROM split_table),
|
|
80
|
+
'_temp'
|
|
81
|
+
) as table_temp
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
WITH table_info AS (
|
|
2
|
+
SELECT
|
|
3
|
+
CASE
|
|
4
|
+
WHEN c.relkind = 'r' THEN 'TABLE'
|
|
5
|
+
WHEN c.relkind = 'p' THEN 'TABLE'
|
|
6
|
+
WHEN c.relkind = 'u' THEN 'UNLOGGED TABLE'
|
|
7
|
+
WHEN c.relkind = 'v' THEN 'VIEW'
|
|
8
|
+
WHEN c.relkind = 'm' THEN 'MATERIALIZED VIEW'
|
|
9
|
+
ELSE 'UNKNOWN'
|
|
10
|
+
END as object_type,
|
|
11
|
+
quote_ident(n.nspname) as schema_name,
|
|
12
|
+
quote_ident(c.relname) as table_name,
|
|
13
|
+
pg_get_partkeydef(c.oid) as partition_by,
|
|
14
|
+
col_description(c.oid, 0) as table_comment,
|
|
15
|
+
am.amname as storage_type,
|
|
16
|
+
c.reloptions as with_options,
|
|
17
|
+
c.oid as table_oid,
|
|
18
|
+
c.relkind as relkind,
|
|
19
|
+
pg_get_viewdef(c.oid) as view_definition
|
|
20
|
+
FROM pg_class as c
|
|
21
|
+
JOIN pg_namespace as n ON c.relnamespace = n.oid
|
|
22
|
+
LEFT JOIN pg_am as am ON c.relam = am.oid
|
|
23
|
+
WHERE c.oid = '{table}'::regclass
|
|
24
|
+
),
|
|
25
|
+
partitions_info AS (
|
|
26
|
+
SELECT
|
|
27
|
+
child.relname as table_partition,
|
|
28
|
+
pg_get_expr(child.relpartbound, child.oid) as partition_constraint
|
|
29
|
+
FROM pg_inherits
|
|
30
|
+
JOIN pg_class child ON pg_inherits.inhrelid = child.oid
|
|
31
|
+
WHERE pg_inherits.inhparent = '{table}'::regclass
|
|
32
|
+
),
|
|
33
|
+
partitions_ddl AS (
|
|
34
|
+
SELECT
|
|
35
|
+
string_agg(
|
|
36
|
+
'CREATE TABLE IF NOT EXISTS ' || (SELECT schema_name FROM table_info) || '.' ||
|
|
37
|
+
CASE
|
|
38
|
+
WHEN (SELECT table_name FROM table_info) ~ '^".*"$' THEN
|
|
39
|
+
'"' || regexp_replace(table_partition, '^"|"$', '', 'g') || '_temp"'
|
|
40
|
+
ELSE
|
|
41
|
+
table_partition || '_temp'
|
|
42
|
+
END ||
|
|
43
|
+
' PARTITION OF ' || (SELECT schema_name FROM table_info) || '.' ||
|
|
44
|
+
CASE
|
|
45
|
+
WHEN (SELECT table_name FROM table_info) ~ '^".*"$' THEN
|
|
46
|
+
'"' || regexp_replace((SELECT table_name FROM table_info), '^"|"$', '', 'g') || '_temp"'
|
|
47
|
+
ELSE
|
|
48
|
+
(SELECT table_name FROM table_info) || '_temp'
|
|
49
|
+
END || ' ' || partition_constraint || ';',
|
|
50
|
+
E'\n'
|
|
51
|
+
) as ddl
|
|
52
|
+
FROM partitions_info
|
|
53
|
+
),
|
|
54
|
+
columns_info AS (
|
|
55
|
+
SELECT
|
|
56
|
+
quote_ident(pa.attname) as column_name,
|
|
57
|
+
format_type(pa.atttypid, pa.atttypmod) as data_type,
|
|
58
|
+
pg_get_expr(ad.adbin, ad.adrelid) as default_value,
|
|
59
|
+
pa.attnotnull as not_null,
|
|
60
|
+
col_description(pa.attrelid, pa.attnum) as column_comment,
|
|
61
|
+
pa.attnum as column_order
|
|
62
|
+
FROM pg_attribute as pa
|
|
63
|
+
LEFT JOIN pg_attrdef as ad ON pa.attrelid = ad.adrelid AND pa.attnum = ad.adnum
|
|
64
|
+
WHERE pa.attrelid = '{table}'::regclass
|
|
65
|
+
AND pa.attnum > 0
|
|
66
|
+
AND NOT pa.attisdropped
|
|
67
|
+
),
|
|
68
|
+
constraints_info AS (
|
|
69
|
+
SELECT DISTINCT
|
|
70
|
+
conname as constraint_name,
|
|
71
|
+
pg_get_constraintdef(oid) as constraint_definition
|
|
72
|
+
FROM pg_constraint
|
|
73
|
+
WHERE conrelid = '{table}'::regclass
|
|
74
|
+
),
|
|
75
|
+
constraints_list AS (
|
|
76
|
+
SELECT
|
|
77
|
+
string_agg(
|
|
78
|
+
' CONSTRAINT ' || quote_ident(constraint_name) || ' ' || constraint_definition,
|
|
79
|
+
',' || E'\n'
|
|
80
|
+
) as constraints_ddl
|
|
81
|
+
FROM constraints_info
|
|
82
|
+
),
|
|
83
|
+
indexes_info AS (
|
|
84
|
+
SELECT
|
|
85
|
+
indexname,
|
|
86
|
+
indexdef
|
|
87
|
+
FROM pg_indexes
|
|
88
|
+
WHERE schemaname = 'mart'
|
|
89
|
+
AND tablename = 'dim_branch'
|
|
90
|
+
),
|
|
91
|
+
indexes_ddl AS (
|
|
92
|
+
SELECT
|
|
93
|
+
string_agg(indexdef || ';', E'\n') as ddl
|
|
94
|
+
FROM indexes_info
|
|
95
|
+
),
|
|
96
|
+
distribution_info AS (
|
|
97
|
+
SELECT
|
|
98
|
+
CASE
|
|
99
|
+
WHEN policytype = 'r' THEN 'DISTRIBUTED RANDOMLY'
|
|
100
|
+
WHEN policytype = 'p' THEN 'DISTRIBUTED BY (' ||
|
|
101
|
+
(SELECT string_agg(quote_ident(a.attname), ', ' ORDER BY pos.ordinality)
|
|
102
|
+
FROM gp_distribution_policy p2
|
|
103
|
+
CROSS JOIN LATERAL unnest(p2.distkey) WITH ORDINALITY AS pos(attnum, ordinality)
|
|
104
|
+
JOIN pg_attribute a ON a.attrelid = p2.localoid AND a.attnum = pos.attnum
|
|
105
|
+
WHERE p2.localoid = '{table}'::regclass) || ')'
|
|
106
|
+
ELSE 'DISTRIBUTED UNKNOWN'
|
|
107
|
+
END as distribution_clause
|
|
108
|
+
FROM gp_distribution_policy
|
|
109
|
+
WHERE localoid = '{table}'::regclass
|
|
110
|
+
),
|
|
111
|
+
table_ddl AS (
|
|
112
|
+
SELECT
|
|
113
|
+
'CREATE ' ||
|
|
114
|
+
CASE
|
|
115
|
+
WHEN (SELECT storage_type FROM table_info) = 'heap' THEN ''
|
|
116
|
+
ELSE 'UNLOGGED '
|
|
117
|
+
END ||
|
|
118
|
+
'TABLE ' || (SELECT schema_name FROM table_info) || '.' || (SELECT table_name FROM table_info) || ' (' || E'\n' ||
|
|
119
|
+
string_agg(
|
|
120
|
+
' ' || ci.column_name || ' ' || ci.data_type ||
|
|
121
|
+
CASE WHEN ci.default_value IS NOT NULL THEN ' DEFAULT ' || ci.default_value ELSE '' END ||
|
|
122
|
+
CASE WHEN ci.not_null THEN ' NOT NULL' ELSE '' END,
|
|
123
|
+
',' || E'\n' ORDER BY ci.column_order
|
|
124
|
+
) ||
|
|
125
|
+
CASE
|
|
126
|
+
WHEN (SELECT constraints_ddl FROM constraints_list) IS NOT NULL THEN
|
|
127
|
+
',' || E'\n' || (SELECT constraints_ddl FROM constraints_list)
|
|
128
|
+
ELSE ''
|
|
129
|
+
END ||
|
|
130
|
+
E'\n' || ')' ||
|
|
131
|
+
CASE WHEN (SELECT partition_by FROM table_info) IS NOT NULL THEN E'\nPARTITION BY ' || (SELECT partition_by FROM table_info) ELSE '' END ||
|
|
132
|
+
CASE WHEN (SELECT storage_type FROM table_info) IS NOT NULL THEN E'\n' || 'USING ' || (SELECT storage_type FROM table_info) ELSE '' END ||
|
|
133
|
+
CASE WHEN (SELECT with_options FROM table_info) IS NOT NULL THEN E'\n' || 'WITH (' || array_to_string((SELECT with_options FROM table_info), ', ') || ')' ELSE '' END ||
|
|
134
|
+
E'\n' || (SELECT distribution_clause FROM distribution_info) || ';' as ddl
|
|
135
|
+
FROM columns_info ci
|
|
136
|
+
WHERE (SELECT relkind FROM table_info) IN ('r', 'p', 'u')
|
|
137
|
+
),
|
|
138
|
+
view_ddl AS (
|
|
139
|
+
SELECT
|
|
140
|
+
'CREATE VIEW ' || (SELECT schema_name FROM table_info) || '.' || (SELECT table_name FROM table_info) ||
|
|
141
|
+
' AS ' || (SELECT view_definition FROM table_info) as ddl
|
|
142
|
+
WHERE (SELECT relkind FROM table_info) = 'v'
|
|
143
|
+
),
|
|
144
|
+
matview_ddl AS (
|
|
145
|
+
SELECT
|
|
146
|
+
'CREATE MATERIALIZED VIEW ' || (SELECT schema_name FROM table_info) || '.' || (SELECT table_name FROM table_info) ||
|
|
147
|
+
' AS ' || (SELECT view_definition FROM table_info) ||
|
|
148
|
+
CASE WHEN (SELECT distribution_clause FROM distribution_info) IS NOT NULL THEN
|
|
149
|
+
E'\n' || (SELECT distribution_clause FROM distribution_info)
|
|
150
|
+
ELSE '' END as ddl
|
|
151
|
+
WHERE (SELECT relkind FROM table_info) = 'm'
|
|
152
|
+
),
|
|
153
|
+
column_comments_ddl AS (
|
|
154
|
+
SELECT
|
|
155
|
+
string_agg(
|
|
156
|
+
'COMMENT ON COLUMN ' || (SELECT schema_name FROM table_info) || '.' || (SELECT table_name FROM table_info) ||
|
|
157
|
+
'.' || column_name || ' IS ' || quote_literal(column_comment) || ';',
|
|
158
|
+
E'\n'
|
|
159
|
+
) as ddl
|
|
160
|
+
FROM columns_info
|
|
161
|
+
WHERE column_comment IS NOT NULL
|
|
162
|
+
),
|
|
163
|
+
table_comment_ddl AS (
|
|
164
|
+
SELECT
|
|
165
|
+
CASE
|
|
166
|
+
WHEN (SELECT table_comment FROM table_info) IS NOT NULL THEN
|
|
167
|
+
'COMMENT ON TABLE ' || (SELECT schema_name FROM table_info) || '.' || (SELECT table_name FROM table_info) ||
|
|
168
|
+
' IS ' || quote_literal((SELECT table_comment FROM table_info)) || ';'
|
|
169
|
+
ELSE ''
|
|
170
|
+
END as ddl
|
|
171
|
+
),
|
|
172
|
+
temp_table_ddl AS (
|
|
173
|
+
SELECT
|
|
174
|
+
'CREATE UNLOGGED TABLE IF NOT EXISTS ' || (SELECT schema_name FROM table_info) || '.' ||
|
|
175
|
+
CASE
|
|
176
|
+
WHEN (SELECT table_name FROM table_info) ~ '^".*"$' THEN
|
|
177
|
+
'"' || regexp_replace((SELECT table_name FROM table_info), '^"|"$', '', 'g') || '_temp"'
|
|
178
|
+
ELSE
|
|
179
|
+
(SELECT table_name FROM table_info) || '_temp'
|
|
180
|
+
END || ' (' || E'\n' ||
|
|
181
|
+
string_agg(
|
|
182
|
+
' ' || ci.column_name || ' ' || ci.data_type ||
|
|
183
|
+
CASE WHEN ci.default_value IS NOT NULL THEN ' DEFAULT ' || ci.default_value ELSE '' END ||
|
|
184
|
+
CASE WHEN ci.not_null THEN ' NOT NULL' ELSE '' END,
|
|
185
|
+
',' || E'\n' ORDER BY ci.column_order
|
|
186
|
+
) || E'\n' || ')' ||
|
|
187
|
+
CASE WHEN (SELECT partition_by FROM table_info) IS NOT NULL THEN
|
|
188
|
+
E'\nPARTITION BY ' || (SELECT partition_by FROM table_info)
|
|
189
|
+
ELSE '' END || ';' ||
|
|
190
|
+
CASE
|
|
191
|
+
WHEN (SELECT ddl FROM partitions_ddl) IS NOT NULL THEN
|
|
192
|
+
E'\n' || E'\n' || (SELECT ddl FROM partitions_ddl)
|
|
193
|
+
ELSE ''
|
|
194
|
+
END as ddl
|
|
195
|
+
FROM columns_info ci
|
|
196
|
+
),
|
|
197
|
+
final_original_ddl AS (
|
|
198
|
+
SELECT
|
|
199
|
+
COALESCE(
|
|
200
|
+
(SELECT ddl FROM table_ddl),
|
|
201
|
+
(SELECT ddl FROM view_ddl),
|
|
202
|
+
(SELECT ddl FROM matview_ddl)
|
|
203
|
+
) ||
|
|
204
|
+
CASE
|
|
205
|
+
WHEN (SELECT ddl FROM indexes_ddl) IS NOT NULL THEN
|
|
206
|
+
E'\n' || (SELECT ddl FROM indexes_ddl)
|
|
207
|
+
ELSE ''
|
|
208
|
+
END ||
|
|
209
|
+
CASE
|
|
210
|
+
WHEN (SELECT ddl FROM table_comment_ddl) != '' THEN
|
|
211
|
+
E'\n' || (SELECT ddl FROM table_comment_ddl)
|
|
212
|
+
ELSE ''
|
|
213
|
+
END ||
|
|
214
|
+
CASE
|
|
215
|
+
WHEN (SELECT ddl FROM column_comments_ddl) IS NOT NULL THEN
|
|
216
|
+
E'\n' || (SELECT ddl FROM column_comments_ddl)
|
|
217
|
+
ELSE ''
|
|
218
|
+
END as original_ddl
|
|
219
|
+
)
|
|
220
|
+
SELECT
|
|
221
|
+
(SELECT original_ddl FROM final_original_ddl) as ddl,
|
|
222
|
+
(SELECT ddl FROM temp_table_ddl) as temp_ddl,
|
|
223
|
+
(SELECT schema_name FROM table_info) || '.' ||
|
|
224
|
+
CASE
|
|
225
|
+
WHEN (SELECT table_name FROM table_info) ~ '^".*"$' THEN
|
|
226
|
+
'"' || regexp_replace((SELECT table_name FROM table_info), '^"|"$', '', 'g') || '_temp"'
|
|
227
|
+
ELSE
|
|
228
|
+
(SELECT table_name FROM table_info) || '_temp'
|
|
229
|
+
END as table_temp
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
WITH table_info AS (
|
|
2
|
+
SELECT
|
|
3
|
+
CASE
|
|
4
|
+
WHEN c.relkind = 'r' THEN 'TABLE'
|
|
5
|
+
WHEN c.relkind = 'p' THEN 'TABLE'
|
|
6
|
+
WHEN c.relkind = 'u' THEN 'UNLOGGED TABLE'
|
|
7
|
+
WHEN c.relkind = 'v' THEN 'VIEW'
|
|
8
|
+
WHEN c.relkind = 'm' THEN 'MATERIALIZED VIEW'
|
|
9
|
+
ELSE 'UNKNOWN'
|
|
10
|
+
END as object_type,
|
|
11
|
+
quote_ident(n.nspname) as schema_name,
|
|
12
|
+
quote_ident(c.relname) as table_name,
|
|
13
|
+
pg_get_partkeydef(c.oid) as partition_by,
|
|
14
|
+
am.amname as storage_type,
|
|
15
|
+
c.reloptions as with_options,
|
|
16
|
+
c.oid as table_oid,
|
|
17
|
+
c.relkind as relkind,
|
|
18
|
+
col_description(c.oid, 0) as table_comment,
|
|
19
|
+
pg_get_viewdef(c.oid) as view_definition
|
|
20
|
+
FROM pg_class as c
|
|
21
|
+
JOIN pg_namespace as n ON c.relnamespace = n.oid
|
|
22
|
+
LEFT JOIN pg_am as am ON c.relam = am.oid
|
|
23
|
+
WHERE c.oid = '{table}'::regclass
|
|
24
|
+
),
|
|
25
|
+
partitions_info AS (
|
|
26
|
+
SELECT
|
|
27
|
+
child.relname as table_partition,
|
|
28
|
+
pg_get_expr(child.relpartbound, child.oid) as partition_constraint
|
|
29
|
+
FROM pg_inherits
|
|
30
|
+
JOIN pg_class child ON pg_inherits.inhrelid = child.oid
|
|
31
|
+
WHERE pg_inherits.inhparent = '{table}'::regclass
|
|
32
|
+
),
|
|
33
|
+
partitions_ddl AS (
|
|
34
|
+
SELECT
|
|
35
|
+
string_agg(
|
|
36
|
+
'CREATE TABLE IF NOT EXISTS ' || (SELECT schema_name FROM table_info) || '.' ||
|
|
37
|
+
CASE
|
|
38
|
+
WHEN (SELECT table_name FROM table_info) ~ '^".*"$' THEN
|
|
39
|
+
'"' || regexp_replace(table_partition, '^"|"$', '', 'g') || '_temp"'
|
|
40
|
+
ELSE
|
|
41
|
+
table_partition || '_temp'
|
|
42
|
+
END ||
|
|
43
|
+
' PARTITION OF ' || (SELECT schema_name FROM table_info) || '.' ||
|
|
44
|
+
CASE
|
|
45
|
+
WHEN (SELECT table_name FROM table_info) ~ '^".*"$' THEN
|
|
46
|
+
'"' || regexp_replace((SELECT table_name FROM table_info), '^"|"$', '', 'g') || '_temp"'
|
|
47
|
+
ELSE
|
|
48
|
+
(SELECT table_name FROM table_info) || '_temp'
|
|
49
|
+
END || ' ' || partition_constraint || ';',
|
|
50
|
+
E'\n'
|
|
51
|
+
) as ddl
|
|
52
|
+
FROM partitions_info
|
|
53
|
+
),
|
|
54
|
+
columns_info AS (
|
|
55
|
+
SELECT
|
|
56
|
+
quote_ident(pa.attname) as column_name,
|
|
57
|
+
format_type(pa.atttypid, pa.atttypmod) as data_type,
|
|
58
|
+
pg_get_expr(ad.adbin, ad.adrelid) as default_value,
|
|
59
|
+
pa.attnotnull as not_null,
|
|
60
|
+
col_description(pa.attrelid, pa.attnum) as column_comment,
|
|
61
|
+
pa.attnum as column_order
|
|
62
|
+
FROM pg_attribute as pa
|
|
63
|
+
LEFT JOIN pg_attrdef as ad ON pa.attrelid = ad.adrelid AND pa.attnum = ad.adnum
|
|
64
|
+
WHERE pa.attrelid = '{table}'::regclass
|
|
65
|
+
AND pa.attnum > 0
|
|
66
|
+
AND NOT pa.attisdropped
|
|
67
|
+
),
|
|
68
|
+
constraints_info AS (
|
|
69
|
+
SELECT DISTINCT
|
|
70
|
+
conname as constraint_name,
|
|
71
|
+
pg_get_constraintdef(oid) as constraint_definition
|
|
72
|
+
FROM pg_constraint
|
|
73
|
+
WHERE conrelid = '{table}'::regclass
|
|
74
|
+
),
|
|
75
|
+
constraints_list AS (
|
|
76
|
+
SELECT
|
|
77
|
+
string_agg(
|
|
78
|
+
' CONSTRAINT ' || quote_ident(constraint_name) || ' ' || constraint_definition,
|
|
79
|
+
',' || E'\n'
|
|
80
|
+
) as constraints_ddl
|
|
81
|
+
FROM constraints_info
|
|
82
|
+
),
|
|
83
|
+
indexes_info AS (
|
|
84
|
+
SELECT
|
|
85
|
+
indexname,
|
|
86
|
+
indexdef
|
|
87
|
+
FROM pg_indexes
|
|
88
|
+
WHERE schemaname = 'mart'
|
|
89
|
+
AND tablename = 'dim_branch'
|
|
90
|
+
),
|
|
91
|
+
indexes_ddl AS (
|
|
92
|
+
SELECT
|
|
93
|
+
string_agg(indexdef || ';', E'\n') as ddl
|
|
94
|
+
FROM indexes_info
|
|
95
|
+
),
|
|
96
|
+
table_ddl AS (
|
|
97
|
+
SELECT
|
|
98
|
+
'CREATE ' ||
|
|
99
|
+
CASE
|
|
100
|
+
WHEN (SELECT storage_type FROM table_info) = 'heap' THEN ''
|
|
101
|
+
ELSE 'UNLOGGED '
|
|
102
|
+
END ||
|
|
103
|
+
'TABLE ' || (SELECT schema_name FROM table_info) || '.' || (SELECT table_name FROM table_info) || ' (' || E'\n' ||
|
|
104
|
+
string_agg(
|
|
105
|
+
' ' || ci.column_name || ' ' || ci.data_type ||
|
|
106
|
+
CASE WHEN ci.default_value IS NOT NULL THEN ' DEFAULT ' || ci.default_value ELSE '' END ||
|
|
107
|
+
CASE WHEN ci.not_null THEN ' NOT NULL' ELSE '' END,
|
|
108
|
+
',' || E'\n' ORDER BY ci.column_order
|
|
109
|
+
) ||
|
|
110
|
+
CASE
|
|
111
|
+
WHEN (SELECT constraints_ddl FROM constraints_list) IS NOT NULL THEN
|
|
112
|
+
',' || E'\n' || (SELECT constraints_ddl FROM constraints_list)
|
|
113
|
+
ELSE ''
|
|
114
|
+
END ||
|
|
115
|
+
E'\n' || ')' ||
|
|
116
|
+
CASE WHEN (SELECT storage_type FROM table_info) IS NOT NULL AND (SELECT storage_type FROM table_info) != 'heap' THEN E'\n' || 'USING ' || (SELECT storage_type FROM table_info) ELSE '' END ||
|
|
117
|
+
CASE WHEN (SELECT with_options FROM table_info) IS NOT NULL THEN E'\n' || 'WITH (' || array_to_string((SELECT with_options FROM table_info), ', ') || ')' ELSE '' END || ';' as ddl
|
|
118
|
+
FROM columns_info ci
|
|
119
|
+
WHERE (SELECT relkind FROM table_info) IN ('r', 'p', 'u')
|
|
120
|
+
),
|
|
121
|
+
view_ddl AS (
|
|
122
|
+
SELECT
|
|
123
|
+
'CREATE VIEW ' || (SELECT schema_name FROM table_info) || '.' || (SELECT table_name FROM table_info) ||
|
|
124
|
+
' AS ' || (SELECT view_definition FROM table_info) as ddl
|
|
125
|
+
WHERE (SELECT relkind FROM table_info) = 'v'
|
|
126
|
+
),
|
|
127
|
+
matview_ddl AS (
|
|
128
|
+
SELECT
|
|
129
|
+
'CREATE MATERIALIZED VIEW ' || (SELECT schema_name FROM table_info) || '.' || (SELECT table_name FROM table_info) ||
|
|
130
|
+
' AS ' || (SELECT view_definition FROM table_info) as ddl
|
|
131
|
+
WHERE (SELECT relkind FROM table_info) = 'm'
|
|
132
|
+
),
|
|
133
|
+
column_comments_ddl AS (
|
|
134
|
+
SELECT
|
|
135
|
+
string_agg(
|
|
136
|
+
'COMMENT ON COLUMN ' || (SELECT schema_name FROM table_info) || '.' || (SELECT table_name FROM table_info) ||
|
|
137
|
+
'.' || column_name || ' IS ' || quote_literal(column_comment) || ';',
|
|
138
|
+
E'\n'
|
|
139
|
+
) as ddl
|
|
140
|
+
FROM columns_info
|
|
141
|
+
WHERE column_comment IS NOT NULL
|
|
142
|
+
),
|
|
143
|
+
table_comment_ddl AS (
|
|
144
|
+
SELECT
|
|
145
|
+
CASE
|
|
146
|
+
WHEN (SELECT table_comment FROM table_info) IS NOT NULL THEN
|
|
147
|
+
'COMMENT ON TABLE ' || (SELECT schema_name FROM table_info) || '.' || (SELECT table_name FROM table_info) ||
|
|
148
|
+
' IS ' || quote_literal((SELECT table_comment FROM table_info)) || ';'
|
|
149
|
+
ELSE ''
|
|
150
|
+
END as ddl
|
|
151
|
+
),
|
|
152
|
+
temp_table_ddl AS (
|
|
153
|
+
SELECT
|
|
154
|
+
'CREATE UNLOGGED TABLE IF NOT EXISTS ' || (SELECT schema_name FROM table_info) || '.' ||
|
|
155
|
+
CASE
|
|
156
|
+
WHEN (SELECT table_name FROM table_info) ~ '^".*"$' THEN
|
|
157
|
+
'"' || regexp_replace((SELECT table_name FROM table_info), '^"|"$', '', 'g') || '_temp"'
|
|
158
|
+
ELSE
|
|
159
|
+
(SELECT table_name FROM table_info) || '_temp'
|
|
160
|
+
END || ' (' || E'\n' ||
|
|
161
|
+
string_agg(
|
|
162
|
+
' ' || ci.column_name || ' ' || ci.data_type ||
|
|
163
|
+
CASE WHEN ci.default_value IS NOT NULL THEN ' DEFAULT ' || ci.default_value ELSE '' END ||
|
|
164
|
+
CASE WHEN ci.not_null THEN ' NOT NULL' ELSE '' END,
|
|
165
|
+
',' || E'\n' ORDER BY ci.column_order
|
|
166
|
+
) || E'\n' || ')' ||
|
|
167
|
+
CASE WHEN (SELECT partition_by FROM table_info) IS NOT NULL THEN
|
|
168
|
+
E'\nPARTITION BY ' || (SELECT partition_by FROM table_info)
|
|
169
|
+
ELSE '' END || ';' ||
|
|
170
|
+
CASE
|
|
171
|
+
WHEN (SELECT ddl FROM partitions_ddl) IS NOT NULL THEN
|
|
172
|
+
E'\n' || E'\n' || (SELECT ddl FROM partitions_ddl)
|
|
173
|
+
ELSE ''
|
|
174
|
+
END as ddl
|
|
175
|
+
FROM columns_info ci
|
|
176
|
+
),
|
|
177
|
+
final_original_ddl AS (
|
|
178
|
+
SELECT
|
|
179
|
+
COALESCE(
|
|
180
|
+
(SELECT ddl FROM table_ddl),
|
|
181
|
+
(SELECT ddl FROM view_ddl),
|
|
182
|
+
(SELECT ddl FROM matview_ddl)
|
|
183
|
+
) ||
|
|
184
|
+
CASE
|
|
185
|
+
WHEN (SELECT ddl FROM indexes_ddl) IS NOT NULL THEN
|
|
186
|
+
E'\n' || (SELECT ddl FROM indexes_ddl)
|
|
187
|
+
ELSE ''
|
|
188
|
+
END ||
|
|
189
|
+
CASE
|
|
190
|
+
WHEN (SELECT ddl FROM table_comment_ddl) != '' THEN
|
|
191
|
+
E'\n' || (SELECT ddl FROM table_comment_ddl)
|
|
192
|
+
ELSE ''
|
|
193
|
+
END ||
|
|
194
|
+
CASE
|
|
195
|
+
WHEN (SELECT ddl FROM column_comments_ddl) IS NOT NULL THEN
|
|
196
|
+
E'\n' || (SELECT ddl FROM column_comments_ddl)
|
|
197
|
+
ELSE ''
|
|
198
|
+
END as original_ddl
|
|
199
|
+
)
|
|
200
|
+
SELECT
|
|
201
|
+
(SELECT original_ddl FROM final_original_ddl) as ddl,
|
|
202
|
+
(SELECT ddl FROM temp_table_ddl) as temp_ddl,
|
|
203
|
+
(SELECT schema_name FROM table_info) || '.' ||
|
|
204
|
+
CASE
|
|
205
|
+
WHEN (SELECT table_name FROM table_info) ~ '^".*"$' THEN
|
|
206
|
+
'"' || regexp_replace((SELECT table_name FROM table_info), '^"|"$', '', 'g') || '_temp"'
|
|
207
|
+
ELSE
|
|
208
|
+
(SELECT table_name FROM table_info) || '_temp'
|
|
209
|
+
END as table_temp
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
select count(*) as value, case when value = 0 then 'Fail' else 'Pass' end as result from {table}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
with
|
|
2
|
+
replaceAll('{table}', '`', '') as table_name
|
|
3
|
+
, splitByChar('.', table_name) as table_parts
|
|
4
|
+
select
|
|
5
|
+
have_test
|
|
6
|
+
, column_name
|
|
7
|
+
, query
|
|
8
|
+
from (
|
|
9
|
+
select
|
|
10
|
+
database
|
|
11
|
+
, table
|
|
12
|
+
, toBool(countIf(type like 'Date%')) as have_test
|
|
13
|
+
from system.columns
|
|
14
|
+
where database = table_parts[1]
|
|
15
|
+
and table = table_parts[2]
|
|
16
|
+
group by 1, 2
|
|
17
|
+
) as ht
|
|
18
|
+
left join (
|
|
19
|
+
select
|
|
20
|
+
name as column_name
|
|
21
|
+
, format(
|
|
22
|
+
'select count(*) as value, if(count() = 0, ''Pass'', ''Fail'') as result \n' ||
|
|
23
|
+
'from {{}} where {{}} > addMonths(today(), 1)'
|
|
24
|
+
, table_name
|
|
25
|
+
, column_name
|
|
26
|
+
) as query
|
|
27
|
+
, database
|
|
28
|
+
, table
|
|
29
|
+
from system.columns
|
|
30
|
+
where database = table_parts[1]
|
|
31
|
+
and table = table_parts[2]
|
|
32
|
+
and type like 'Date%'
|
|
33
|
+
) as qt
|
|
34
|
+
using(database, table)
|