All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.ebeaninternal.dbmigration.builtin-extra-ddl-partitioning.xml Maven / Gradle / Ivy

The newest version!
<?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
    );
  end if;
end$$;

------------------------------------------------------------------------------------
-- Function: _partition_create
--
-- Internal helper method to create a partition given meta data
------------------------------------------------------------------------------------
create or replace function _partition_create(meta partition_meta)
  returns text
language plpgsql
set timezone to 'UTC'
as $$
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);
  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)
  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)
    into meta.period_name, meta.base_name, meta.part_name;

  return meta;
end;
$$;

------------------------------------------------------------------------------------
-- 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', 4);
--   select partition('month', 'event', 1);
--
------------------------------------------------------------------------------------
create or replace function partition(
  mode           text,                       -- one of 'day','week','month','year'
  baseName       text,                       -- base table name
  partitionCount integer default 0,          -- number of additional partitions
  fromDate       date default current_date)  -- date to create first partition for
  returns text
language plpgsql
set timezone to 'UTC'
as $$
begin
  perform _partition_create(_partition_meta(mode, poDate, baseName))
  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');
--
------------------------------------------------------------------------------------
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
  partitionCount integer default 0,          -- number of additional partitions
  fromDate       date default current_date)  -- date to create first partition for
  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);
  meta.period_start = initDate;
  perform _partition_create(meta);

  if (partitionCount > 0) then
    -- create additional partitions normally
    fromDate = fromDate + interval '1 day';
    perform _partition_create(_partition_meta(mode, poDate, baseName))
    from _partition_over(mode, fromDate, partitionCount) poDate;
  end if;

  return 'done';
end;
$$;
</ddl-script>

</extra-ddl>




© 2015 - 2024 Weber Informatics LLC | Privacy Policy