Add truncating according to interval and minor fixes

velioglu/create_timeseries_table
Burak Velioglu 2021-08-20 01:53:26 +03:00
parent ef724edf31
commit e9bb732b22
No known key found for this signature in database
GPG Key ID: F6827E620F6549C6
2 changed files with 61 additions and 36 deletions

View File

@ -13,19 +13,14 @@ DECLARE
current_partition_count int; current_partition_count int;
BEGIN BEGIN
/* /*
* TODO: Check whether the table is timeseries table with INTERVAL partition range * First check whether such timeseries table exists. If not, error out.
* and timestamptz partition column *
*/
/*
* Then check if start_from is given. If it is, create the partition for that time * Then check if start_from is given. If it is, create the partition for that time
* and let remaining of the function fill the gap from start_from to to_date. * and let remaining of the function fill the gap from start_from to to_date.
* *
* TODO: That part is implemented by assuming that there is no partition exist for * TODO: That part is implemented by assuming that there is no partition exist for
* the given table, in other words that function will be called via create_timeseries_table * the given table, in other words that function will be called via create_timeseries_table
* only. * only. That will be handled while adding starting time for old data ingestion (Task 1.3)
*
* TODO: Handle date trunc according to given interval of the timeseries table
*/ */
SELECT partitioninterval SELECT partitioninterval
@ -33,11 +28,32 @@ BEGIN
FROM citus_timeseries.citus_timeseries_tables FROM citus_timeseries.citus_timeseries_tables
WHERE logicalrelid = table_name; WHERE logicalrelid = table_name;
IF NOT found THEN
RAISE '% must be timeseries table', table_name;
END IF;
IF start_from IS NOT NULL THEN IF start_from IS NOT NULL THEN
RAISE NOTICE 'IN START FROM'; /*
* Decide on the current_range_from_value of the initial partition according to interval of the timeseries table.
* Since we will create all other partitions by adding intervals, truncating given start time will provide
* more intuitive interval ranges.
*/
IF table_partition_interval < INTERVAL '1 hour' THEN
current_range_from_value = date_trunc('minute', start_from);
ELSIF table_partition_interval < INTERVAL '1 day' THEN
current_range_from_value = date_trunc('hour', start_from);
ELSIF table_partition_interval < INTERVAL '1 week' THEN
current_range_from_value = date_trunc('day', start_from);
ELSIF table_partition_interval < INTERVAL '1 month' THEN
current_range_from_value = date_trunc('week', start_from);
ELSIF table_partition_interval < INTERVAL '1 year' THEN
current_range_from_value = date_trunc('month', start_from);
ELSE
current_range_from_value = date_trunc('year', start_from);
END IF;
current_partition_count := 0; current_partition_count := 0;
current_range_from_value := start_from; current_range_to_value := current_range_from_value + table_partition_interval;
current_range_to_value := start_from + table_partition_interval;
current_partition_name := table_name::text || '_' || current_partition_count::text; current_partition_name := table_name::text || '_' || current_partition_count::text;
EXECUTE format('CREATE TABLE %I PARTITION OF %I FOR VALUES FROM (''%I'') TO (''%I'')', current_partition_name, table_name::text, current_range_from_value::text, current_range_to_value::text); EXECUTE format('CREATE TABLE %I PARTITION OF %I FOR VALUES FROM (''%I'') TO (''%I'')', current_partition_name, table_name::text, current_range_from_value::text, current_range_to_value::text);
@ -59,9 +75,7 @@ BEGIN
FROM pg_catalog.time_partitions FROM pg_catalog.time_partitions
WHERE parent_table = table_name; WHERE parent_table = table_name;
RAISE NOTICE 'current_range_from_value %', current_range_from_value; WHILE current_range_to_value < to_date LOOP
WHILE current_range_from_value < to_date LOOP
current_range_from_value := current_range_to_value; current_range_from_value := current_range_to_value;
current_range_to_value := current_range_to_value + table_partition_interval; current_range_to_value := current_range_to_value + table_partition_interval;
current_partition_name := table_name::text || '_' || current_partition_count::text; current_partition_name := table_name::text || '_' || current_partition_count::text;
@ -69,14 +83,13 @@ BEGIN
-- TODO: Create that using attach partition, which can be implemented with another UDF to make sure that it gets light locks. -- TODO: Create that using attach partition, which can be implemented with another UDF to make sure that it gets light locks.
BEGIN BEGIN
EXECUTE format('CREATE TABLE %I PARTITION OF %I FOR VALUES FROM (''%I'') TO (''%I'')', current_partition_name, table_name::text, current_range_from_value::text, current_range_to_value::text); EXECUTE format('CREATE TABLE %I PARTITION OF %I FOR VALUES FROM (''%I'') TO (''%I'')', current_partition_name, table_name::text, current_range_from_value::text, current_range_to_value::text);
EXCEPTION WHEN OTHERS THEN
raise notice 'Partition has already been created for the range from % to %', current_range_from_value::text, current_range_to_value::text;
END;
current_partition_count := current_partition_count + 1; current_partition_count := current_partition_count + 1;
EXCEPTION WHEN OTHERS THEN
raise DEBUG3 'Partition has already been created for the range from % to %', current_range_from_value::text, current_range_to_value::text;
END;
END LOOP; END LOOP;
return true; RETURN true;
END; END;
$$; $$;
COMMENT ON FUNCTION pg_catalog.create_missing_partitions( COMMENT ON FUNCTION pg_catalog.create_missing_partitions(

View File

@ -13,19 +13,14 @@ DECLARE
current_partition_count int; current_partition_count int;
BEGIN BEGIN
/* /*
* TODO: Check whether the table is timeseries table with INTERVAL partition range * First check whether such timeseries table exists. If not, error out.
* and timestamptz partition column *
*/
/*
* Then check if start_from is given. If it is, create the partition for that time * Then check if start_from is given. If it is, create the partition for that time
* and let remaining of the function fill the gap from start_from to to_date. * and let remaining of the function fill the gap from start_from to to_date.
* *
* TODO: That part is implemented by assuming that there is no partition exist for * TODO: That part is implemented by assuming that there is no partition exist for
* the given table, in other words that function will be called via create_timeseries_table * the given table, in other words that function will be called via create_timeseries_table
* only. * only. That will be handled while adding starting time for old data ingestion (Task 1.3)
*
* TODO: Handle date trunc according to given interval of the timeseries table
*/ */
SELECT partitioninterval SELECT partitioninterval
@ -33,11 +28,32 @@ BEGIN
FROM citus_timeseries.citus_timeseries_tables FROM citus_timeseries.citus_timeseries_tables
WHERE logicalrelid = table_name; WHERE logicalrelid = table_name;
IF NOT found THEN
RAISE '% must be timeseries table', table_name;
END IF;
IF start_from IS NOT NULL THEN IF start_from IS NOT NULL THEN
RAISE NOTICE 'IN START FROM'; /*
* Decide on the current_range_from_value of the initial partition according to interval of the timeseries table.
* Since we will create all other partitions by adding intervals, truncating given start time will provide
* more intuitive interval ranges.
*/
IF table_partition_interval < INTERVAL '1 hour' THEN
current_range_from_value = date_trunc('minute', start_from);
ELSIF table_partition_interval < INTERVAL '1 day' THEN
current_range_from_value = date_trunc('hour', start_from);
ELSIF table_partition_interval < INTERVAL '1 week' THEN
current_range_from_value = date_trunc('day', start_from);
ELSIF table_partition_interval < INTERVAL '1 month' THEN
current_range_from_value = date_trunc('week', start_from);
ELSIF table_partition_interval < INTERVAL '1 year' THEN
current_range_from_value = date_trunc('month', start_from);
ELSE
current_range_from_value = date_trunc('year', start_from);
END IF;
current_partition_count := 0; current_partition_count := 0;
current_range_from_value := start_from; current_range_to_value := current_range_from_value + table_partition_interval;
current_range_to_value := start_from + table_partition_interval;
current_partition_name := table_name::text || '_' || current_partition_count::text; current_partition_name := table_name::text || '_' || current_partition_count::text;
EXECUTE format('CREATE TABLE %I PARTITION OF %I FOR VALUES FROM (''%I'') TO (''%I'')', current_partition_name, table_name::text, current_range_from_value::text, current_range_to_value::text); EXECUTE format('CREATE TABLE %I PARTITION OF %I FOR VALUES FROM (''%I'') TO (''%I'')', current_partition_name, table_name::text, current_range_from_value::text, current_range_to_value::text);
@ -52,7 +68,6 @@ BEGIN
INTO current_range_from_value, current_range_to_value INTO current_range_from_value, current_range_to_value
FROM pg_catalog.time_partitions FROM pg_catalog.time_partitions
WHERE parent_table = table_name WHERE parent_table = table_name
ORDER BY from_value::timestamptz; ORDER BY from_value::timestamptz;
SELECT count(*) SELECT count(*)
@ -60,25 +75,22 @@ BEGIN
FROM pg_catalog.time_partitions FROM pg_catalog.time_partitions
WHERE parent_table = table_name; WHERE parent_table = table_name;
RAISE NOTICE 'current_range_from_value %', current_range_from_value; WHILE current_range_to_value < to_date LOOP
WHILE current_range_from_value < to_date LOOP
current_range_from_value := current_range_to_value; current_range_from_value := current_range_to_value;
current_range_to_value := current_range_to_value + table_partition_interval; current_range_to_value := current_range_to_value + table_partition_interval;
current_partition_name := table_name::text || '_' || current_partition_count::text; current_partition_name := table_name::text || '_' || current_partition_count::text;
-- TODO: Create that using attach partition, which can be implemented with another UDF to make sure that it gets light locks. -- TODO: Create that using attach partition, which can be implemented with another UDF to make sure that it gets light locks.
-- TODO: Add exception handling or partition check
BEGIN BEGIN
EXECUTE format('CREATE TABLE %I PARTITION OF %I FOR VALUES FROM (''%I'') TO (''%I'')', current_partition_name, table_name::text, current_range_from_value::text, current_range_to_value::text); EXECUTE format('CREATE TABLE %I PARTITION OF %I FOR VALUES FROM (''%I'') TO (''%I'')', current_partition_name, table_name::text, current_range_from_value::text, current_range_to_value::text);
EXCEPTION WHEN OTHERS THEN EXCEPTION WHEN OTHERS THEN
raise notice 'oops %', sqlstate; raise DEBUG3 'Partition has already been created for the range from % to %', current_range_from_value::text, current_range_to_value::text;
END; END;
current_partition_count := current_partition_count + 1; current_partition_count := current_partition_count + 1;
END LOOP; END LOOP;
return true; RETURN true;
END; END;
$$; $$;
COMMENT ON FUNCTION pg_catalog.create_missing_partitions( COMMENT ON FUNCTION pg_catalog.create_missing_partitions(