253 lines
10 KiB
MySQL
253 lines
10 KiB
MySQL
|
DROP FUNCTION IF EXISTS public.generate_partitioning_of_an_existing_table_by_date_unix_time(text, text, integer, integer, text, boolean);
|
||
|
|
||
|
CREATE OR REPLACE FUNCTION public.generate_partitioning_of_an_existing_table_by_date_unix_time(
|
||
|
tablename text,
|
||
|
columnname text,
|
||
|
start_year integer,
|
||
|
end_year integer,
|
||
|
step text,
|
||
|
droptable boolean DEFAULT false)
|
||
|
RETURNS void
|
||
|
LANGUAGE 'plpgsql'
|
||
|
|
||
|
VOLATILE PARALLEL UNSAFE
|
||
|
AS $BODY$
|
||
|
declare old_tablename TEXT;
|
||
|
new_tablename TEXT;
|
||
|
partition_tablename TEXT;
|
||
|
start_interval TEXT;
|
||
|
end_interval TEXT;
|
||
|
interations INTEGER;
|
||
|
i INTEGER;
|
||
|
sql_str TEXT = '';
|
||
|
receive_constraints TEXT;
|
||
|
receive_triggers TEXT;
|
||
|
toBeDeleted_constraints TEXT;
|
||
|
lastvalue INTEGER;
|
||
|
exists_sequence TEXT;
|
||
|
tmp_sql VARCHAR;
|
||
|
renamed_indexes TEXT;
|
||
|
renamed_constraints TEXT;
|
||
|
toBeCreated_indexes TEXT;
|
||
|
start_unix_time TEXT;
|
||
|
end_unix_time TEXT;
|
||
|
primary_key TEXT;
|
||
|
sequence_id TEXT;
|
||
|
|
||
|
BEGIN
|
||
|
|
||
|
IF start_year > end_year THEN
|
||
|
RAISE NOTICE '%', 'start_year > end_year';
|
||
|
RETURN;
|
||
|
END IF;
|
||
|
|
||
|
primary_key := '"posID"';
|
||
|
sequence_id := '_posID_seq';
|
||
|
|
||
|
new_tablename := 'new_' || tablename;
|
||
|
sql_str := format('-- create a new table having the same structure with specified table ' || CHR(13) ||
|
||
|
'CREATE TABLE ' || new_tablename || '(LIKE ' || tablename || ' INCLUDING DEFAULTS INCLUDING CONSTRAINTS) PARTITION BY RANGE(' || columnname || ');' || CHR(13) || CHR(13) ||
|
||
|
'-- create partiton for all other records that dont match with the partition condition' || CHR(13) ||
|
||
|
'CREATE TABLE ' || tablename || '_default PARTITION OF ' || new_tablename || ' DEFAULT; ') || CHR(13);
|
||
|
|
||
|
|
||
|
sql_str := sql_str || CHR(13) || get_query_partitioning_of_an_existing_table_by_date_unix_time(tablename , new_tablename, start_year, end_year, step);
|
||
|
|
||
|
sql_str := sql_str || CHR(13) ||
|
||
|
'-- copy data into the new table ' || CHR(13) ||
|
||
|
'INSERT INTO ' || new_tablename || '(SELECT * FROM ' || tablename || '); ' || CHR(13) ;
|
||
|
|
||
|
|
||
|
RAISE NOTICE '%', sql_str;
|
||
|
|
||
|
-- execute the query
|
||
|
EXECUTE sql_str;
|
||
|
|
||
|
--===========================================================
|
||
|
-- build the commands to rename the indexes
|
||
|
--===========================================================
|
||
|
|
||
|
old_tablename := tablename;
|
||
|
|
||
|
SELECT string_agg( 'ALTER INDEX IF EXISTS "' || indexname || '" RENAME TO "old_' || indexname || '";' , CHR(13)) INTO renamed_indexes
|
||
|
FROM pg_indexes pg
|
||
|
WHERE pg.tablename = old_tablename
|
||
|
AND indexname NOT LIKE '%pkey%';
|
||
|
|
||
|
SELECT string_agg( CASE WHEN contype = 'p' THEN -- primary key
|
||
|
'ALTER INDEX IF EXISTS "' || conname || '" RENAME TO "old_' || conname || '";'
|
||
|
ELSE
|
||
|
'ALTER TABLE ' || old_tablename || ' RENAME CONSTRAINT "' || conname || '" TO "old_' || conname || '";'
|
||
|
END
|
||
|
, CHR(13)) INTO renamed_constraints
|
||
|
|
||
|
FROM pg_catalog.pg_constraint con
|
||
|
INNER JOIN pg_catalog.pg_class rel ON rel.oid = con.conrelid
|
||
|
WHERE rel.relname = old_tablename;
|
||
|
|
||
|
--======================================================================
|
||
|
-- build the commands to recreate the indexes on the partitioned table
|
||
|
--======================================================================
|
||
|
|
||
|
SELECT string_agg( indexdef || ';' , CHR(13)) INTO toBeCreated_indexes
|
||
|
FROM pg_indexes pg
|
||
|
WHERE pg.tablename = old_tablename
|
||
|
AND indexname NOT LIKE '%pkey%'
|
||
|
AND indexname NOT LIKE '%' || primary_key || '%'
|
||
|
AND indexdef NOT LIKE '%UNIQUE%';
|
||
|
|
||
|
|
||
|
|
||
|
--===========================================================
|
||
|
-- save the foreign key into receive_constraints variable
|
||
|
--===========================================================
|
||
|
SELECT string_agg(command , CHR(13) ) INTO receive_constraints
|
||
|
FROM ( SELECT format('ALTER TABLE IF EXISTS "%s" ADD CONSTRAINT "%s" FOREIGN KEY ("%s") REFERENCES "%s"("%s");',
|
||
|
tablename,
|
||
|
tc.constraint_name,
|
||
|
string_agg(distinct kcu.column_name, ','),
|
||
|
ccu.table_name,
|
||
|
string_agg(distinct ccu.column_name, ',')) command
|
||
|
FROM information_schema.table_constraints AS tc
|
||
|
JOIN information_schema.key_column_usage AS kcu
|
||
|
ON tc.constraint_name = kcu.constraint_name
|
||
|
JOIN information_schema.constraint_column_usage AS ccu
|
||
|
ON ccu.constraint_name = tc.constraint_name
|
||
|
WHERE constraint_type = 'FOREIGN KEY'
|
||
|
AND tc.table_name = tablename
|
||
|
GROUP BY tc.constraint_name, tc.table_name, ccu.table_name
|
||
|
)x;
|
||
|
|
||
|
--===========================================================
|
||
|
-- save the triggers into receive_triggers variable
|
||
|
--===========================================================
|
||
|
SELECT string_agg(command , CHR(13) ) INTO receive_triggers
|
||
|
FROM ( SELECT format( 'CREATE TRIGGER %s %s %s ON "%s" FOR EACH ROW %s ;',
|
||
|
t1.trigger_name
|
||
|
,t1.action_timing
|
||
|
,t2.event_manipulation
|
||
|
,t1.event_object_table
|
||
|
,t1.action_statement ) as command
|
||
|
|
||
|
FROM ( SELECT DISTINCT
|
||
|
trigger_name
|
||
|
,action_timing
|
||
|
,event_object_table
|
||
|
,action_statement
|
||
|
FROM information_schema.triggers
|
||
|
WHERE event_object_table = tablename
|
||
|
) t1
|
||
|
INNER JOIN (SELECT trigger_name, string_agg(event_manipulation, ' OR ') as event_manipulation
|
||
|
FROM information_schema.triggers
|
||
|
WHERE event_object_table = tablename
|
||
|
GROUP BY trigger_name
|
||
|
) t2 ON t1.trigger_name = t2.trigger_name
|
||
|
)x;
|
||
|
|
||
|
|
||
|
--===================================================================================================================
|
||
|
-- save the constraints which refereces the specified tablename into toBeDeleted_constraints variable
|
||
|
--===================================================================================================================
|
||
|
SELECT string_agg( 'ALTER TABLE IF EXISTS "' || foreign_table || '" DROP CONSTRAINT IF EXISTS "' || constraint_name || '";' , CHR(13) ) INTO toBeDeleted_constraints
|
||
|
FROM (
|
||
|
select kcu.table_name as foreign_table,
|
||
|
'>-' as rel,
|
||
|
rel_tco.table_schema || '.' || rel_tco.table_name as primary_table,
|
||
|
string_agg(kcu.column_name, ', ') as fk_columns,
|
||
|
kcu.constraint_name
|
||
|
from information_schema.table_constraints tco
|
||
|
join information_schema.key_column_usage kcu
|
||
|
on tco.constraint_schema = kcu.constraint_schema
|
||
|
and tco.constraint_name = kcu.constraint_name
|
||
|
join information_schema.referential_constraints rco
|
||
|
on tco.constraint_schema = rco.constraint_schema
|
||
|
and tco.constraint_name = rco.constraint_name
|
||
|
join information_schema.table_constraints rel_tco
|
||
|
on rco.unique_constraint_schema = rel_tco.constraint_schema
|
||
|
and rco.unique_constraint_name = rel_tco.constraint_name
|
||
|
where tco.constraint_type = 'FOREIGN KEY'
|
||
|
and rel_tco.table_name = tablename
|
||
|
group by kcu.table_schema,
|
||
|
kcu.table_name,
|
||
|
rel_tco.table_name,
|
||
|
rel_tco.table_schema,
|
||
|
kcu.constraint_name
|
||
|
)x;
|
||
|
|
||
|
tmp_sql = ' SELECT ''exists'' FROM pg_class WHERE relname = ''' || tablename || sequence_id || ''';';
|
||
|
EXECUTE tmp_sql INTO exists_sequence;
|
||
|
|
||
|
--RAISE NOTICE '%', COALESCE( exists_sequence, 'not exists');
|
||
|
IF exists_sequence = 'exists' THEN
|
||
|
EXECUTE format(' SELECT last_value FROM "%s";', tablename || sequence_id) INTO lastvalue;
|
||
|
END IF;
|
||
|
|
||
|
|
||
|
|
||
|
IF ( dropTable ) THEN
|
||
|
|
||
|
sql_str := '--====== dropTable = true ======-- ' || CHR(13) || CHR(13) ||
|
||
|
'-- drop old table with cascade ' || CHR(13) ||
|
||
|
'DROP TABLE IF EXISTS ' || tablename || ' CASCADE; ' || CHR(13) ||
|
||
|
|
||
|
'-- rename the new table to old table ' || CHR(13) ||
|
||
|
'ALTER TABLE IF EXISTS ' || new_tablename || ' RENAME TO ' || tablename || ';' || CHR(13) ||
|
||
|
|
||
|
'-- create primary key ' || CHR(13) ||
|
||
|
'ALTER TABLE IF EXISTS ' || tablename || ' ADD CONSTRAINT ' || tablename || '_pkey PRIMARY KEY (' || primary_key || ',' || columnname || ');' || CHR(13) ||
|
||
|
|
||
|
'-- create sequence ' || CHR(13) ||
|
||
|
'CREATE SEQUENCE IF NOT EXISTS "' || tablename || sequence_id || '" INCREMENT 1 START ' || COALESCE(lastvalue,0) + 1 || ';' || CHR(13) ||
|
||
|
|
||
|
'-- set id to be taken from sequence ' || CHR(13) ||
|
||
|
'ALTER TABLE IF EXISTS ' || tablename || ' ALTER COLUMN ' || primary_key || ' SET DEFAULT nextval(''"' || tablename || sequence_id || '"'');' || CHR(13);
|
||
|
|
||
|
|
||
|
ELSE
|
||
|
|
||
|
sql_str := COALESCE( renamed_constraints, '') || CHR(13) ||
|
||
|
COALESCE( renamed_indexes, '') || CHR(13);
|
||
|
EXECUTE sql_str;
|
||
|
|
||
|
sql_str := '--====== dropTable = false ( rename table )======-- ' || CHR(13) || CHR(13) ||
|
||
|
|
||
|
'-- rename the current table to *_old ' || CHR(13) ||
|
||
|
'ALTER TABLE IF EXISTS ' || tablename || ' RENAME TO ' || tablename || '_old; ' || CHR(13) ||
|
||
|
|
||
|
'-- rename the new table ' || CHR(13) ||
|
||
|
'ALTER TABLE IF EXISTS ' || new_tablename || ' RENAME TO ' || tablename || ';' || CHR(13) ||
|
||
|
|
||
|
'-- create primary key ' || CHR(13) ||
|
||
|
'ALTER TABLE IF EXISTS ' || tablename || ' ADD CONSTRAINT ' || tablename || '_pkey PRIMARY KEY (' || primary_key || ',' || columnname || ');' || CHR(13) ||
|
||
|
|
||
|
'-- rename existing sequence as old ' || CHR(13) ||
|
||
|
'ALTER SEQUENCE IF EXISTS "' || tablename || sequence_id || '" RENAME TO "' || tablename || '_old' || sequence_id || '";' || CHR(13) ||
|
||
|
|
||
|
'-- create sequence ' || CHR(13) ||
|
||
|
'CREATE SEQUENCE IF NOT EXISTS "' || tablename || sequence_id || '" INCREMENT 1 START ' || COALESCE(lastvalue,0) + 1 || ';' || CHR(13) ||
|
||
|
|
||
|
'-- set id to be taken from sequence ' || CHR(13) ||
|
||
|
'ALTER TABLE IF EXISTS ' || tablename || '_old' || ' ALTER COLUMN ' || primary_key || ' SET DEFAULT nextval(''"' || tablename || '_old' || sequence_id || '"'');' || CHR(13) ||
|
||
|
|
||
|
'-- set id to be taken from sequence ' || CHR(13) ||
|
||
|
'ALTER TABLE IF EXISTS ' || tablename || ' ALTER COLUMN ' || primary_key || ' SET DEFAULT nextval(''"' || tablename || sequence_id || '"'');' || CHR(13);
|
||
|
|
||
|
END IF;
|
||
|
|
||
|
sql_str := sql_str || COALESCE(toBeDeleted_constraints, '') || CHR(13) || COALESCE(receive_constraints, '') || CHR(13) || CHR(13) || COALESCE(receive_triggers, '');
|
||
|
|
||
|
|
||
|
RAISE NOTICE '%', sql_str;
|
||
|
|
||
|
-- execute the query
|
||
|
EXECUTE sql_str;
|
||
|
|
||
|
|
||
|
sql_str := COALESCE(toBeCreated_indexes, '');
|
||
|
|
||
|
RAISE NOTICE '%', sql_str;
|
||
|
EXECUTE sql_str;
|
||
|
|
||
|
END;
|
||
|
$BODY$;
|