
io.ebeaninternal.dbmigration.builtin-extra-ddl-partitioning.xml Maven / Gradle / Ivy
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <extra-ddl xmlns="http://ebean-orm.github.io/xml/ns/extraddl"> <ddl-script name="partition help" init="true" platforms="postgres"> -- partitioning helper functions (UTC based) ------------------------------------------------------------------------------------ -- Type: partition_meta -- -- Type used to hold common partitioning parameters such as period start and end etc ------------------------------------------------------------------------------------ do $$ begin if not exists (select 1 from pg_type where typname = 'partition_meta') THEN create type partition_meta as ( period_start timestamptz, period_end timestamptz, period_name text, base_name text, part_name text, unique_column text, index_column text ); end if; end$$; ------------------------------------------------------------------------------------ -- Function: _partition_create -- -- Internal helper method to create a partition given meta data and -- optional extra function to call (typically to create additional indexes) ------------------------------------------------------------------------------------ create or replace function _partition_create(meta partition_meta, extra text) returns text language plpgsql set timezone to 'UTC' as $$ declare idx_col text; idx_name text; begin execute format('create table if not exists %I partition of %I for values from (''%s'') TO (''%s'')', meta.part_name, meta.base_name, meta.period_start, meta.period_end); if (length(meta.unique_column) > 0) then execute format('create unique index if not exists uq_%I ON %I (%I)', meta.part_name, meta.part_name, meta.unique_column); end if; if (length(meta.index_column) > 0) then -- delimited for multiple indexes foreach idx_col in array regexp_split_to_array(meta.index_column,';') loop idx_name = replace(idx_col, ',', '_'); execute format('create index if not exists ix_%I_%s ON %I (%s)', meta.part_name, idx_name, meta.part_name, idx_col); end loop; end if; if (length(extra) > 0) then execute 'select ' || extra || '($1)' using meta; end if; return meta.part_name; end; $$; ------------------------------------------------------------------------------------ -- Function: _partition_meta -- -- Internal helper method to create and return meta data used to create a partition. -- Helps work out start and end periods for day, week, month and year partitions. ------------------------------------------------------------------------------------ create or replace function _partition_meta( mode text, asOf date, baseName text, uniqueColumn text, indexColumn text) returns partition_meta language plpgsql set timezone to 'UTC' as $$ declare partName text; meta partition_meta; asOfUtc timestamptz; begin asOfUtc = timezone('utc', asOf); if (mode = 'day') then asOfUtc = date_trunc('day', asOfUtc); partName = to_char(asOfUtc, 'YYYY_MM_DD'); select asOfUtc, asOfUtc + interval '1 days' into meta.period_start, meta.period_end; elseif (mode = 'week') then asOfUtc = date_trunc('week', asOfUtc); partName = format('%s_w%s', extract(ISOYEAR FROM asOfUtc), extract(WEEK FROM asOfUtc)); select asOfUtc, asOfUtc + interval '7 days' into meta.period_start, meta.period_end; elseif (mode = 'year') then asOfUtc = date_trunc('year', asOfUtc); partName = to_char(date_trunc('year', asOfUtc), 'YYYY'); select asOfUtc, asOfUtc + interval '1 year' into meta.period_start, meta.period_end; else asOfUtc = date_trunc('month', asOfUtc); partName = to_char(asOfUtc, 'YYYY_MM'); select asOfUtc, asOfUtc + interval '1 month' into meta.period_start, meta.period_end; end if; select partName, baseName, format('%s_%s', baseName, partName), uniqueColumn, indexColumn into meta.period_name, meta.base_name, meta.part_name, meta.unique_column, meta.index_column; return meta; end; $$; create or replace function _partition_meta_initdate( meta partition_meta, initDate date) returns partition_meta language plpgsql set timezone to 'UTC' as $$ begin meta.period_start = initDate; return meta; end; $$; -- select _partition_over('week', current_date, 4); ------------------------------------------------------------------------------------ -- Function: _partition_over -- -- Internal helper method to return a set/table of dates to ensure partitions exists for. -- Typically we want to ensure some future partitions exist and this helps return dates -- for which we loop to create partitions. ------------------------------------------------------------------------------------ create or replace function _partition_over( mode text, fromDate date default current_date, _count integer default 0) returns TABLE(of_date date) language plpgsql as $$ declare endDate date; begin if (mode = 'day') then endDate = fromDate + (interval '1 day' * _count); fromDate = fromDate - interval '1 day'; -- allow for timezone return query select s::date from generate_series(fromDate, endDate, '1 day') s; elseif (mode = 'week') then fromDate = date_trunc('week', fromDate); endDate = fromDate + (interval '1 week' * _count); return query select s::date from generate_series(fromDate, endDate, '1 week') s; elseif (mode = 'year') then fromDate = date_trunc('year', fromDate); endDate = fromDate + (interval '1 year' * _count); return query select s::date from generate_series(fromDate, endDate, '1 year') s; else fromDate = date_trunc('month', fromDate); endDate = fromDate + (interval '1 month' * _count); return query select s::date from generate_series(fromDate, endDate, '1 month') s; end if; end; $$; ------------------------------------------------------------------------------------ -- Function: partition -- -- Helper to ensure we create partitions into the future as needed for day, week, month -- and year based partitioning. Typically we call this periodically (e.g. every day). -- -- Examples: -- -- select partition('week', 'trip', 'id', 'when_started', 4); -- select partition('month', 'event', 'id', 'event_timestamp', 1); -- ------------------------------------------------------------------------------------ create or replace function partition( mode text, -- one of 'day','week','month','year' baseName text, -- base table name uniqueColumn text, -- optional unique column indexColumn text, -- optional column to index partitionCount integer default 0, -- number of additional partitions fromDate date default current_date, -- date to create first partition for extra text default '') -- custom function to call per partition returns text language plpgsql set timezone to 'UTC' as $$ begin perform _partition_create(_partition_meta(mode, poDate, baseName, uniqueColumn, indexColumn), extra) from _partition_over(mode, fromDate, partitionCount) poDate; return 'done'; end; $$; ------------------------------------------------------------------------------------ -- Function: partition_init -- -- Similar to partition but allows the first partition to be bigger with an explicit -- initDate typically to allow back dated rows to go into the initial partition. -- -- Examples: -- -- select partition_init(date '2001-01-01', 'week', 'event', 'id', 'event_timestamp', 4); -- ------------------------------------------------------------------------------------ create or replace function partition_init( initDate date, -- first partition period start date mode text, -- one of 'day','week','month','year' baseName text, -- base table name uniqueColumn text, -- optional unique column indexColumn text, -- optional column to index partitionCount integer default 0, -- number of additional partitions fromDate date default current_date, -- date to create first partition for extra text default '') -- custom function to call per partition returns text language plpgsql set timezone to 'UTC' as $$ declare meta partition_meta; begin -- override the period start for the first partition meta = _partition_meta(mode, fromDate, baseName, uniqueColumn, indexColumn); meta = _partition_meta_initdate(meta, initDate); perform _partition_create(meta, extra); if (partitionCount > 0) then -- create additional migrations normally perform _partition_create(_partition_meta(mode, poDate, baseName, uniqueColumn, indexColumn), extra) from _partition_over(mode, fromDate, partitionCount) poDate; end if; return 'done'; end; $$; </ddl-script> </extra-ddl>
© 2015 - 2025 Weber Informatics LLC | Privacy Policy