2012-04-07 4 views
1

私は、PostgreSQL 9.1でコンテンツストレージ用のテーブルを動的に作成するフレームワークを開発中です。 API関数の1つは、呼び出し元が指定されたオブジェクト(たとえば、Webフォーム)内のすべてのフィールドを指定することによって、新しいコンテンツエントリを保存できるようにします。一連のフィールドを受け取るために、フレームワークは複合型を作成します。このような私は明示的なキャストを追加する必要があり、この関数を呼び出すために、今すぐplpgsql関数で複合型の明示的なキャストを避けることはできますか?

CREATE SEQUENCE seq_contents MINVALUE 10000; 
CREATE TABLE contents (
    content_id  int8  not null, 
    is_edited  boolean  not null default false, 
    is_published boolean  not null default false, 
    "Input1"  varchar(60), 
    "CheckBox1"  int2, 
    "TheBox"  varchar(60), 
    "Slider1"  varchar(60) 
); 
CREATE TYPE "contentsType" AS (
    "Input1"  varchar(60), 
    "CheckBox1"  int2, 
    "TheBox"  varchar(60), 
    "Slider1"  varchar(60) 
); 
CREATE OR REPLACE FUNCTION push(in_all anyelement) RETURNS int8 AS $push$ 
DECLARE 
    _c_id int8; 
BEGIN 
    SELECT nextval('seq_contents') INTO _c_id; 

    EXECUTE $$INSERT INTO contents 
    SELECT a.*, b.* 
     FROM (SELECT $1, true, false) AS a, 
      (SELECT $2.*) AS b$$ USING _c_id, in_all; 

    RETURN _c_id; 
END; 
$push$ LANGUAGE plpgsql; 

は、次のコードを考えてみましょう

SELECT push(('input1',1,'thebox','slider1')::"contentsType"); 

明示的なキャストを回避する方法はありますか?外部の呼び出し元がキャストを処理しないようにしたい、つまりPostgreSQLの機能の背後にあるロジックを隠すことができます。現在、私はこのようなエラーがあります:

SELECT push(('input1',1,'thebox','slider1')); 
ERROR: PL/pgSQL functions cannot accept type record 
CONTEXT: compilation of PL/pgSQL function "push" near line 1 
+0

「PL/pgSQL関数は型レコードを受け取ることができません」というエラーに基づいて、これはPL/pgSQLの問題であると想定しています。だからオプションの1つがCでこの機能を作っているかもしれません。 – vyegorov

答えて

1

のテキスト表現としてレコード変数を渡すと考えましたか? 理論上、すべてのレコード変数は、通常のCAST演算子を使用してテキストとの間でキャストできます。

CREATE OR REPLACE FUNCTION push(in_all text) RETURNS int8 AS $push$ 
DECLARE 
    _c_id int8; 
BEGIN 
    SELECT nextval('seq_contents') INTO _c_id; 

    EXECUTE $$INSERT INTO contents 
    SELECT a.*, b.* 
     FROM (SELECT $1, true, false) AS a, 
      (SELECT $2.*) AS b$$ USING _c_id, in_all::"contentsType"; 

    RETURN _c_id; 
END; 
$push$ LANGUAGE plpgsql; 

そしてそれは

(タイプへの明示的な参照)、このように呼び出すことができない。ここ

in_allがテキストを入力しており、USING句で"contentsType"にキャストされますように修飾された関数であります

またはそのような

select push('(input1,1,thebox,slider1)'); 

SELECT push(('input1',1,'thebox','slider1')::"contentsType"::text); 
(明示的なレコードはテキストにキャスト)

これは、 "contentsType"だけでなく、他のレコードタイプでも機能し、そのタイプに戻すことができると仮定します。

はまたplpgsqlが、私はこれは同様に動作するはずと仮定します。

ret := push(r::text); 

rはレコード変数です。

+0

私は自分自身でテキスト表現を使用しています。この点を指摘してくれてありがとう、私はこの解決策に行き、パフォーマンスが許容できない場合に備えて 'C'関数で動作します。 – vyegorov

1

あなたが挿入したいテーブル名をハードコーディングしている、とあなたはそれが必要なパラメータの固定数と種類を持っているので、私は理由については明らかではありませんよ"contentsType"タイプが必要です。関数呼び出しから余分なレベルのカッコを取り除いて4つのパラメータを直接渡すのはなぜですか?それはすべてをより簡単に保ちます。

SELECT push('input1',1,'thebox','slider1'); 

あなたはそれがすべてのテーブルのために動作するようにプッシュ()関数を一般化するために探している場合ならば、あなたは他の問題をヒットされます:このような機能を見て呼び出します

CREATE OR REPLACE FUNCTION push(
    "Input1"  varchar(60), 
    "CheckBox1"  int2, 
    "TheBox"  varchar(60), 
    "Slider1"  varchar(60) 
) RETURNS int8 AS $push$ 
DECLARE 
    _c_id int8; 
BEGIN 
    SELECT nextval('seq_contents') INTO _c_id; 

    EXECUTE $$INSERT INTO contents 
    VALUES ($1, true, false, $2, %3, %4, $5) 
     $$ USING _c_id, "Input1", "CheckBox1", "TheBox", "Slider1"); 

    RETURN _c_id; 
END; 
$push$ LANGUAGE plpgsql; 

あなたはこれを過ぎてしまいます。実行中に関数がテーブル名を知る必要があるという事実を乗り越えることはできません。各レコードタイプに対して別々のpush()を持つことができるように関数をオーバーロードする場合は、レコードタイプに関する情報を何らかの形で提供する必要があります。このようなことをする場合は、質問への短い答えは「いいえ」です。

一方、これは必要以上に難しくなっている可能性があります。私はあなたがテーブルと同じ名前で、すべてのテーブルのために作成された型が自動的にあることを知っていることを願っています。おそらく型を明示的に宣言することと、テーブルと同じ名前のレコードを渡すことの両方を行うために、関数が満たす値のためのダミーエントリを使用することができます。私はplpgsqlの強いタイピング問題を乗り越えるのは難しいかもしれませんが、完全に汎用的なプッシュ関数を作ることができると思います。あなたがそれに精通しているなら、C言語で関数を書く方が簡単かもしれません。

+0

それは一例です。実際には表の名前(この例では 'contents')は、複合型の構造と構造が異なります。表/型の名前、列の番号、列の名前、列。 – vyegorov

+0

もう1つのコメント。私は本当に一般化された 'push()'関数を持っていたいと思います。テーブルには外部の呼び出し元に公開しないいくつかの余分なフィールドがあるので、PostgreSQLで作成した型をテーブルに使用することはできません。私はプッシュを過負荷にしたくない。だから私はCの機能に固執します。ご回答有難うございます。 – vyegorov