Self-managing PostgreSQL partition tables

前端 未结 4 976
深忆病人
深忆病人 2021-01-03 08:52

I am trying to make a self-managing partition table setup with Postgres. It all revolves around this function but I can\'t seem to get Postgres to accept my table names. Any

4条回答
  •  情歌与酒
    2021-01-03 09:49

    I figured out the entirety and it works great, even have an auto-delete after 30 days. I hope this helps out future people looking for an autopartition trigger function.

    CREATE FUNCTION ping_partition() RETURNS trigger
        LANGUAGE plpgsql
        AS $_$
    DECLARE
    _keepdate text;
    _tablename text;
    _startdate text;
    _enddate text;
    _result record;
    BEGIN
    _keepdate:=to_char(to_timestamp(NEW.date) - interval '30 days', 'YYYY-MM-DD');
    _startdate := to_char(to_timestamp(NEW.date), 'YYYY-MM-DD');
    _tablename:='pings_'||NEW.id||'_'||_startdate;
    PERFORM 1
    FROM   pg_catalog.pg_class c
    JOIN   pg_catalog.pg_namespace n ON n.oid = c.relnamespace
    WHERE  c.relkind = 'r'
    AND    c.relname = _tablename
    AND    n.nspname = 'pinglog';
    IF NOT FOUND THEN
        _enddate:=_startdate::timestamp + INTERVAL '1 day';
        EXECUTE 'CREATE TABLE pinglog.' || quote_ident(_tablename) || ' (
            CHECK ( date >= EXTRACT(EPOCH FROM DATE ' || quote_literal(_startdate) || ')
                AND date < EXTRACT(EPOCH FROM DATE ' || quote_literal(_enddate) || ')
                AND id = ' || quote_literal(NEW.id) || '
            )
        ) INHERITS (pinglog.pings)';
        EXECUTE 'CREATE INDEX ' || quote_ident(_tablename||'_indx1') || ' ON pinglog.' || quote_ident(_tablename) || ' USING btree (microseconds) WHERE microseconds IS NULL';
        EXECUTE 'CREATE INDEX ' || quote_ident(_tablename||'_indx2') || ' ON pinglog.' || quote_ident(_tablename) || ' USING btree (date, id)';
        EXECUTE 'CREATE INDEX ' || quote_ident(_tablename||'_indx3') || ' ON pinglog.' || quote_ident(_tablename) || ' USING btree (date, id, microseconds) WHERE microseconds IS NULL';
    END IF;
    EXECUTE 'INSERT INTO ' || quote_ident(_tablename) || ' VALUES ($1.*)' USING NEW;
    FOR _result IN SELECT * FROM pg_tables WHERE schemaname='pinglog' LOOP
        IF char_length(substring(_result.tablename from '[0-9-]*$')) <> 0 AND (to_timestamp(NEW.date) - interval '30 days') > to_timestamp(substring(_result.tablename from '[0-9-]*$'),'YYYY-MM-DD') THEN
            -- RAISE EXCEPTION 'timestamp=%,table=%,found=%',to_timestamp(substring(_result.tablename from '[0-9-]*$'),'YYYY-MM-DD'),_result.tablename,char_length(substring(_result.tablename from '[0-9-]*$'));
            -- could have it check for non-existant ids as well, or for archive bit and only delete if the archive bit is not set
            EXECUTE 'DROP TABLE ' || quote_ident(_result.tablename);
        END IF;
    END LOOP;
    RETURN NULL;
    END;
    $_$;
    

提交回复
热议问题