2012-02-06 24 views
1

クライアントは何かを別のテーブルに保存しようとしています。 (ロングストーリー、それは必需品です)。 これを行うには、独自の名前空間で新しいテーブルを作成するPostgres関数を構築しました。PostgreSQL - 動的テーブル、関数内のテキスト配列から値を挿入

これらの表は、2,4、または100の列を持つことができます。 問題はありませんが、これは機能します。これらの動的表の使用されるデータ型は、ネイティブです(例:テキスト、ブーリアン、整数など。

問題が発生しました。これらのテーブルにデータを挿入する必要があります。ポイントは、ユーザーがテーブルに直接アクセスすることはできません、彼らは機能を通じてこれを行うでしょう。

これは問題ではありませんが、テキストデータ型では問題があります。

-- Function: add(integer, text[]) 

-- DROP FUNCTION add(integer, text[]); 

CREATE OR REPLACE FUNCTION add(id integer, fields text[]) 
    RETURNS integer AS 
$BODY$ 
DECLARE 
l_line_ending text := ')'; 
    l_fieldtype integer; 
    l_ito_table_name text; 
    l_ito_fieldnames text; 
    l_field ito_fields%rowtype; 
    l_first_loop boolean := true; 
    l_values_to_insert text := 'VALUES ('; 
    l_loop_counter integer := 0; 
    l_query text; 

BEGIN 
    select into l_ito_table_name ito_table_name from ito where id = target_ito_id; 
    l_ito_fieldnames := 'insert into ' || l_ito_table_name || '('; 
    FOR l_field IN SELECT * FROM ito_fields 
    WHERE ito_fields.ito_id = target_ito_id 
    order by ito_fields.id asc 
    LOOP 
     l_loop_counter := l_loop_counter +1; 
     l_fieldtype := l_field.fieldtype; 
     if not l_first_loop THEN 
      l_values_to_insert := (l_values_to_insert || ', '); 
     end if; 
     if l_field.fieldtype = 1 THEN 
      l_values_to_insert := (l_values_to_insert || '''' || (fields[l_loop_counter]) || ''''); 
     elsif l_field.fieldtype = 2 THEN 
      l_values_to_insert := quote_literal(l_values_to_insert || private.cast_to_integer(fields[l_loop_counter])); 
     elsif l_field.fieldtype = 3 THEN 
      l_values_to_insert := quote_literal(l_values_to_insert || private.cast_to_boolean(fields[l_loop_counter])); 
     elsif l_field.fieldtype = 4 THEN 
      l_values_to_insert := quote_literal(l_values_to_insert || private.cast_to_float(fields[l_loop_counter])); 
     else 
      return 103; 
     end if; 
     if l_first_loop then 
      l_ito_fieldnames := l_ito_fieldnames || l_field.column_name; 
      l_first_loop := false; 
     else 
      l_ito_fieldnames := l_ito_fieldnames || ', ' || l_field.column_name; 
     end if; 
    END LOOP; 
    l_ito_fieldnames := l_ito_fieldnames || l_line_ending; 
    l_values_to_insert := ((l_values_to_insert) || (l_line_ending)); 
    l_query := (l_ito_fieldnames || l_values_to_insert); 
    EXECUTE l_query; 
    return 0; 

END; 
$BODY$ 
    LANGUAGE plpgsql VOLATILE 
    COST 100; 
ALTER FUNCTION add(integer, text[]) 
    OWNER TO postgres; 

表は店舗すべてのフィールドのメタデータをito_fields、そのデータ型は、バージョンは、説明はここに格納されています。ここでは

は、今までの関数です。 itoテーブルには、すべての動的テーブルデータが格納されます。

この機能のポイントは引用符です。 insert関数は動的に作成されるので、insert関数のテキストフィールドの前後に引用符を追加する必要があります。 Postgresはすぐにエラーを出しています。 quote_literal関数でさえ、文字列の連結のためにまだ問題です(私はセキュリティ上のリスクがあることは知っていますが、今のところ問題ありません)。

私はquote_literal、quote_identを使用しようとしましたが、実行関数(replace(query、l_quote_rep、 '' ''))まで引用符( ')を置き換えても。 。。手がかり今どのようにこの問題を解決するには...事前に

おかげ

答えて

1

Arraysaggregatesquote_ident and quote_nullableはあなたの友達である

これは動作するはずですし、コードが短くなって:

CREATE OR REPLACE FUNCTION add(id integer, fields text[]) 
    RETURNS integer AS 
$BODY$ 
DECLARE 
    l_ito_table_name text; 
    l_query text; 
    l_fields text; 
    r_values text; 
BEGIN 
    --get table name 
    SELECT INTO l_ito_table_name quote_ident(ito_table_name) FROM ito WHERE id = target_ito_id; 
    -- get column names 
    SELECT INTO l_fields 
    array_to_string(array_agg(quote_ident(column_name)), ',') 
    FROM ito_fields 
    WHERE ito_fields.ito_id = target_ito_id 
    order by ito_fields.id asc; 
    -- prepare values 
    SELECT INTO r_values 
    array_to_string(array_agg(quote_nullable(u.name)), ',') 
    FROM unnest(fields) u(name); 
    l_query := 'insert into ' || l_ito_table_name || '(' || l_fields || ') values (' || r_values || ')'; 
    EXECUTE l_query; 
    return 0; -- why 0? 
END; 
$BODY$; 
+0

0は標準の「成功」コードです。 正しいデータ型へのキャストがいくつかありません。アイデアは、すべてのフィールドがテキストとして挿入されるのではなく、そのネイティブデータ型に挿入されるということです。 (現在サポートされている:テキスト、整数、ブール、倍精度)。 (現時点でテストする可能性はありません) – Reneger

+0

原則として、テキストから他のデータ型へのキャストが存在する必要があります。 – filiprem

関連する問題