[pgsql-jp: 40047] EXECUTE USINGについて
Yusuke Yamasaki
tm9233yy @ gmail.com
2009年 11月 4日 (水) 17:27:16 JST
山崎(ゆ)といいます。
環境: CentOS5.4, PostgreSQL 8.4.1
ログデータを格納するテーブルをパーティションに分け、
自動管理するようなBEFORE INSERTトリガを書いてみました。
下記§4のサンプルで、テーブルがない場合は作成する機能を追加したものです。
http://lets.postgresql.jp/documents/technical/partitioning/2#detail
4. 動的SQLによる INSERT の分配
6. CREATE TABLE LINE 構文によるインデックス定義の自動化
動作したコードが、下記(1)になります。
そこで質問ですが、PostgreSQL8.4ではEXECUTE USINGというのが使えるとのことですが、
この機能の使い方がよくわかりません。
newを渡すことはできるようですが、他の変数も並べるとエラーになってしまいました。
文字連結で見にくくなるのを避けるのに使おうと思っただけなんですが、
そういう使い方はできないんでしょうか?
下記(2)のコードでは、
=# insert into events select * from events;
ERROR: relation "$2" does not exist
行 1: CREATE TABLE "$1" (LIKE "$2" INCLUDING INDEXES INCLUDING DEF...
^
QUERY: CREATE TABLE "$1" (LIKE "$2" INCLUDING INDEXES INCLUDING
DEFAULTS INCLUDING CONSTRAINTS, CHECK ('$3' <= '$4' AND '$4' < '$5'))
INHERITS ("$2")
CONTEXT: PL/pgSQL function "event_insert_trigger" line 17 at EXECUTE statement
というエラーになります。
(1) 動作するSQL
CREATE OR REPLACE FUNCTION event_insert_trigger() RETURNS TRIGGER AS
$$
DECLARE
parent text := 'events';
part text; -- パーティション・テーブルの名前
t_cur timestamp;
t_beg timestamp;
t_end timestamp;
BEGIN
-- パーティション名 : parent_YYMM
part := parent || '_' || to_char(new.created_at, 'YYMM');
IF NOT EXISTS(select * from information_schema.tables where
table_name = part) THEN
-- 振り分けの上限・下限
t_cur := new.created_at;
t_beg := to_timestamp(to_char(t_cur, 'YYYY-MM-01 00:00:00'),
'YYYY-MM-DD HH24:MI:SS');
t_end := t_beg + '1 month';
EXECUTE 'CREATE TABLE ' ||part|| ' (LIKE ' ||parent|| ' INCLUDING
INDEXES INCLUDING DEFAULTS INCLUDING CONSTRAINTS, '
|| 'CHECK (' ||quote_literal(t_beg)|| ' <= '
||quote_literal(t_cur)|| ' AND ' ||quote_literal(t_cur)|| ' < '
||quote_literal(t_end)|| ')'
|| ') INHERITS (' ||parent|| ')';
END IF;
-- new を渡す
EXECUTE 'INSERT INTO ' || part || ' VALUES(($1).*)' USING new;
RETURN NULL;
END;
$$ LANGUAGE plpgsql;
-- トリガを作成
CREATE TRIGGER event_insert_trigger_instance
BEFORE INSERT ON events
FOR EACH ROW EXECUTE PROCEDURE event_insert_trigger();
(2) エラーになるSQL
CREATE OR REPLACE FUNCTION event_insert_trigger() RETURNS TRIGGER AS
$$
DECLARE
parent text := 'events';
part text; -- パーティション・テーブルの名前
t_cur timestamp;
t_beg timestamp;
t_end timestamp;
BEGIN
-- パーティション名 : parent_YYMM
part := parent || '_' || to_char(new.created_at, 'YYMM');
IF NOT EXISTS(select * from information_schema.tables where
table_name = part) THEN
-- 振り分けの上限・下限
t_cur := new.created_at;
t_beg := to_timestamp(to_char(t_cur, 'YYYY-MM-01 00:00:00'),
'YYYY-MM-DD HH24:MI:SS');
t_end := t_beg + '1 month';
EXECUTE 'CREATE TABLE "$1" ('
|| 'LIKE "$2" INCLUDING INDEXES INCLUDING DEFAULTS INCLUDING CONSTRAINTS, '
|| 'CHECK (''$3'' <= ''$4'' AND ''$4'' < ''$5'')'
|| ') INHERITS ("$2")'
USING part, parent, t_beg, t_cur, t_end;
END IF;
EXECUTE 'INSERT INTO "$1" VALUES(($2).*)' USING part, new;
RETURN NULL;
END;
$$ LANGUAGE 'plpgsql';
-- トリガを作成
CREATE TRIGGER event_insert_trigger_instance
BEFORE INSERT ON events
FOR EACH ROW EXECUTE PROCEDURE event_insert_trigger();
--
Yusuke Yamasaki <tm9233yy @ gmail.com>
pgsql-jp メーリングリストの案内