テーブルにパーティションを追加する関数がありますが、これは問題なく機能します。スキーマ名、テーブル名、および日付を受け取り、ALTER TABLE
ステートメントを生成して実行し、指定された日付のパーティションを追加します。
オーバーフローパーティションに存在するデータに基づいて日付範囲を生成し、最初の関数を呼び出してオーバーフローパーティションを日付ごとに新しいパーティションに分割する別の関数があります。
ただし、次のエラーで失敗するため、この方法で実行することはできないと思います。
ERROR: relation 6712928 is still open (relcache.c:2417)
これは、すべての変更ステートメントを並行して実行しようとしているためだと思います。誰かがステートメントを一度に1つずつ実行する方法を考えることができますか?
FORループでクエリを実行し、ループの反復ごとに1回関数を呼び出してみましたが、同じことを行います。
これが私の2つの機能です:
CREATE OR REPLACE FUNCTION dv_util.create_partition(p_schema character varying, p_table character varying, p_date date) RETURNS boolean AS
$BODY$
DECLARE
splitter varchar(10000);
counter integer;
BEGIN
splitter := 'ALTER TABLE '||p_schema||'.'||p_table||' SPLIT DEFAULT PARTITION START ('''||p_date::text||'''::date) INCLUSIVE END ('''||(p_date + interval '1 days')::date::text||'''::date) EXCLUSIVE INTO (PARTITION "'||p_date::text||'", default partition)';
SELECT count(*) INTO counter FROM information_schema.tables WHERE table_schema = p_schema AND table_name = p_table;
IF counter > 0 THEN -- table exists
SELECT count(*) INTO counter FROM information_schema.tables WHERE table_schema = p_schema AND table_name = p_table||'_1_prt_'||p_date::text;
IF counter = 0 THEN -- partition does not exist
EXECUTE splitter;
RETURN true;
ELSE
RETURN false;
END IF;
ELSE
RETURN false;
END IF;
END;
$BODY$
LANGUAGE plpgsql VOLATILE;
CREATE OR REPLACE FUNCTION dv_util.add_partitions(p_schema character varying, p_table character varying) RETURNS boolean AS
$BODY$
DECLARE
adder varchar(10000); -- Query to generate all the partition parameters
c_adding refcursor; -- Cursor to iterate over the partiton parameters
q_add RECORD;
result boolean;
counter integer;
BEGIN
adder := 'with source as (SELECT * FROM '||p_schema||'.'||p_table||')';
adder := adder || ', over as (SELECT * FROM '||p_schema||'.'||p_table||'_1_prt_overflow)';
adder := adder || ', series as ';
adder := adder || '(SELECT generate_series( greatest(';
adder := adder || ' ( least( coalesce((select min(std_date_utc) from over),current_date)';
adder := adder || ' , coalesce((select (max(std_date_utc) + interval ''1 day'')::date from source)),current_date) - ''2001-01-01'')::integer';
adder := adder || ' , 0 )::integer';
adder := adder || ' , (greatest( (select max(std_date_utc) from over)';
adder := adder || ' , current_date + interval ''30 day'')::date - ''2001-01-01'')::integer ))';
adder := adder || 'select ((''2001-01-01''::date) + (generate_series * (interval ''1 day'')))::date dd from series';
SELECT count(*) INTO counter FROM information_schema.tables WHERE table_schema = p_schema AND table_name = p_table||'_1_prt_overflow';
IF counter > 0 THEN
FOR q_add IN EXECUTE adder LOOP
SELECT dv_util.create_partition(p_schema,p_table,q_add.dd) INTO result;
END LOOP;
RETURN true;
ELSE
RETURN false;
END IF;
END;
$BODY$
LANGUAGE plpgsql VOLATILE;
これは、テーブル上でカーソルが開いている(アクティブ選択)ときに、パーティションを追加するようにテーブルを変更しようとしているために発生しています。必要なロックが競合しています。最初にパーティションの日付を配列にフェッチし、カーソルを閉じてから、その配列からパーティションを作成することで、これを修正できます。コードサンプルは以下のとおりです。
CREATE OR REPLACE FUNCTION dv_util.add_partitions(p_schema character varying, p_table character varying) RETURNS boolean AS
$BODY$
DECLARE
adder varchar(10000); -- Query to generate all the partition parameters
c_adding refcursor; -- Cursor to iterate over the partiton parameters
q_add RECORD;
result boolean;
counter integer;
p_part_dates date[];
part_cntr int;
BEGIN
adder := 'with source as (SELECT * FROM '||p_schema||'.'||p_table||')';
adder := adder || ', over as (SELECT * FROM '||p_schema||'.'||p_table||'_1_prt_overflow)';
adder := adder || ', series as ';
adder := adder || '(SELECT generate_series( greatest(';
adder := adder || ' ( least( coalesce((select min(std_date_utc) from over),current_date)';
adder := adder || ' , coalesce((select (max(std_date_utc) + interval ''1 day'')::date from source)),current_date) - ''2001-01-01'')::integer';
adder := adder || ' , 0 )::integer';
adder := adder || ' , (greatest( (select max(std_date_utc) from over)';
adder := adder || ' , current_date + interval ''30 day'')::date - ''2001-01-01'')::integer ))';
adder := adder || 'select ((''2001-01-01''::date) + (generate_series * (interval ''1 day'')))::date dd from series';
SELECT count(*) INTO counter FROM information_schema.tables WHERE table_schema = p_schema AND table_name = p_table||'_1_prt_overflow';
IF counter > 0 THEN
part_cntr := 0;
FOR q_add IN EXECUTE adder LOOP
part_cntr := part_cntr + 1;
p_part_dates[part_cntr] = q_add.dd;
-- SELECT dv_util.create_partition(p_schema,p_table,q_add.dd) INTO result;
END LOOP;
for i in 1..part_cntr loop
select dv_util.create_partition(p_schema,p_table,p_part_dates[i]) INTO result;
end loop;
RETURN true;
ELSE
RETURN false;
END IF;
END;
$BODY$
LANGUAGE plpgsql VOLATILE;