-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathnumeric_serials_bigger_than_bigint.sql
71 lines (66 loc) · 3.11 KB
/
numeric_serials_bigger_than_bigint.sql
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
CREATE OR REPLACE FUNCTION numeric_serials_bigger_than_bigint(schema_name regnamespace)
/*
Checks for all NUMERIC greater than 18 digits if it's possible to convert them to bigint (said in column 'downcast_possible')
The function can check it in one schema or in all the database:
- SELECT * FROM numeric_serials_bigger_than_bigint('my_schema');
- SELECT * FROM numeric_serials_bigger_than_bigint(null);
*/
RETURNS TABLE (
table_schema information_schema.sql_identifier, --regnamespace,
table_name information_schema.sql_identifier, --regclass,
column_name VARCHAR(1000),
column_default VARCHAR(1000),
is_nullable boolean,
data_type VARCHAR(50),
numeric_precision INT,
numeric_scale INT,
n_live_tup NUMERIC(100),
min_value NUMERIC(100),
max_value NUMERIC(100),
downcast_possible boolean
)
LANGUAGE plpgsql
AS $$
DECLARE
min_return NUMERIC(100);
max_return NUMERIC(100);
serial_row RECORD;
BEGIN
CREATE TEMPORARY TABLE serials (
table_schema information_schema.sql_identifier NOT NULL, --regnamespace NOT NULL,
table_name information_schema.sql_identifier NOT NULL, --regclass NOT NULL,
column_name VARCHAR(1000) NOT NULL,
column_default VARCHAR(1000) NOT NULL,
is_nullable boolean NOT NULL,
data_type VARCHAR(50) NOT NULL,
numeric_precision INT NOT NULL,
numeric_scale INT NOT NULL,
n_live_tup NUMERIC(100) NOT NULL,
min_value NUMERIC(100),
max_value NUMERIC(100),
downcast_possible boolean
) ON COMMIT DROP;
INSERT INTO serials (table_schema, table_name, column_name, column_default, is_nullable, data_type,
numeric_precision, numeric_scale, n_live_tup)
SELECT c.table_schema, c.table_name, c.column_name, c.column_default, CAST (c.is_nullable AS boolean), c.data_type,
c.numeric_precision, c.numeric_scale, t.n_live_tup
FROM information_schema.columns c
INNER JOIN pg_stat_user_tables t ON c.table_schema = t.schemaname AND c.table_name = t.relname
WHERE c.data_type = 'numeric' AND c.numeric_precision > 18 AND c.column_default LIKE 'nextval(''%'
AND c.table_schema = COALESCE(CAST(schema_name AS information_schema.sql_identifier), c.table_schema)
ORDER BY c.table_catalog, c.table_schema, c.table_name, c.column_name;
FOR serial_row IN
SELECT s.table_schema, s.table_name, s.column_name,
'SELECT MIN(' || s.column_name || '), MAX(' || s.column_name || ') FROM ' || s.table_schema || '.' || s.table_name AS sql_code
FROM serials s
LOOP
EXECUTE serial_row.sql_code INTO min_return, max_return;
UPDATE serials s SET min_value = min_return, max_value = max_return, downcast_possible = TRUE
WHERE s.table_schema = serial_row.table_schema AND s.table_name = serial_row.table_name AND s.column_name = serial_row.column_name;
UPDATE serials s SET downcast_possible = (s.numeric_precision > LOG(s.max_value))
WHERE s.max_value IS NOT NULL;
END LOOP;
RETURN QUERY SELECT s.table_schema, s.table_name, s.column_name, s.column_default, s.is_nullable, s.data_type,
s.numeric_precision, s.numeric_scale, s.n_live_tup, s.min_value, s.max_value, s.downcast_possible FROM serials s;
END;
$$;