在Postgres 9.6的分区表上插入失败

时间:2019-06-19 16:32:33

标签: function triggers partition postgres-9.6

我有一张大桌子,我们需要每月进行分区。该表当前是另一个表的子级。我试图在此表上创建一个分区,这些分区将要从原始父表继承。我已经创建了触发器和函数,并且旧的子表保存了触发器以创建分区。

Tables:
parent_table (Partitioned tables are going to be inherited from this table)
old_child_table (This holds the trigger, code will try to insert here)

CREATE OR REPLACE FUNCTION temp.partition_insert_function()
RETURNS TRIGGER
AS $$
DECLARE
partition_month TEXT;
partition_schema TEXT;
partition_name TEXT;
start_of_month TEXT;
end_of_month TEXT;
BEGIN
partition_month := to_char(NEW.created_dtm,'YYYY_MM'); ---This column  has a default of now() and it is of timestamp with timezone
partition_schema := 'temp';
partition_name := 'partition_' || partition_month;
start_of_month := to_char((NEW.created_dtm),'YYYY-MM'|| '-01');
end_of_month := to_char((NEW.created_dtm + interval '1 month'),'YYYY-MM'|| '-01');

EXECUTE format('INSERT INTO %I.%I VALUES($1.*) ON CONFLICT (primary_key) DO NOTHING', partition_schema, partition_name) using NEW;
---I want to try to insert first rather than checking every time if the partition exists or not.

RETURN NULL;

EXCEPTION WHEN SQLSTATE '42P01' THEN

RAISE NOTICE 'RELNAME %', TG_TABLE_NAME;

IF NOT EXISTS  ---If the insert fails for above SQLSTATE then I want to check if the partition exists or not
(SELECT 1
 FROM   information_schema.tables
 WHERE  table_name = partition_name
 AND table_schema = partition_schema) 
THEN
EXECUTE 'CREATE TABLE ' || partition_schema || '.' || partition_name || ' (check (created_dtm >= ''' || start_of_month || ''' and created_dtm < ''' || end_of_month || ''' ), ' || 'LIKE temp.old_child_table  INCLUDING ALL)  INHERITS (temp.parent_table)';
EXECUTE 'ALTER TABLE ' || partition_schema || '.' || partition_name || ' OWNER TO owner';
EXECUTE 'GRANT SELECT ON TABLE ' || partition_schema || '.' || partition_name || ' TO user_ro';
EXECUTE 'GRANT INSERT, SELECT, UPDATE, DELETE ON TABLE ' || partition_schema || ' . ' || partition_name || ' TO user_rw';
EXECUTE 'ALTER TABLE ' || partition_schema || '.' || partition_name || '  ADD CONSTRAINT ' || partition_name || '_fkey1 FOREIGN KEY(random_key) REFERENCES temp.random(random_key)';
EXECUTE 'CREATE TRIGGER ' || partition_name || '_trigger1  BEFORE INSERT OR UPDATE ON ' || partition_schema || '.' || partition_name || ' FOR EACH  ROW EXECUTE PROCEDURE temp.trigger_function()';
RAISE NOTICE 'A partition has been created %.%', partition_schema, partition_name;
RAISE NOTICE 'All FK constraints are created on %.%', partition_schema, partition_name;
RAISE NOTICE 'All necessary indices are created on %.%', partition_schema, partition_name;
RAISE NOTICE 'All triggers are created on %.%', partition_schema, partition_name;
END IF;

EXECUTE format('INSERT INTO %I.%I VALUES($1.*) ON CONFLICT (primary_key) DO NOTHING', partition_schema, partition_name) using NEW;

RETURN NULL;
END
$$
LANGUAGE plpgsql;

CREATE TRIGGER insert_trigger
BEFORE INSERT
ON temp.old_child_table
FOR EACH ROW
EXECUTE PROCEDURE temp.partition_insert_function();

It gives me below error;
ERROR:  new row for relation "partition_2018_04" violates check constraint "partition_2018_04_created_dtm_check"

我还尝试在old_child_table上创建视图并在该视图上创建触发器,但这给了我同样的错误。理想情况下,我们想在视图上创建它,因为我们想获取返回的primary_key。在函数中,我还尝试替换RETURN NULL或RETURN NEW,并且错误仍然相同。

注意:在第一个插入本身上会引发此错误,并且由于该错误而不会创建任何分区。

0 个答案:

没有答案