web-dev-qa-db-ja.com

CREATEステートメントの準備

その場でビューを作成するようにしています。
私の場合は、EAVスタイルのテーブルのピボットビューです。

2つの属性を含むテーブルを想定して、トリガー関数(PL/Pythonで記述)内で実行される次のようなステートメントを使用します。

CREATE OR REPLACE VIEW pivot_eav AS 
  SELECT ct.id,
         ct.attr1,
         ct.attr2
  FROM crosstab(
    '
      SELECT entity, attribute, value
      FROM eav_table
      ORDER BY 1
    '::text,
    '
      VALUES (''attr1''), (''attr2'')
    '::text
    )
  AS ct(id    text,
        attr1 text,
        attr2 text
    );

しかし、今では、作成時に2つの属性の名前がわかりません。実行時に挿入する必要があります。その場でステートメントを作成して実行できます。実際、それは私が現時点で行っていることです。

"""
CREATE OR REPLACE VIEW pivot_eav AS 
  SELECT ct.id,
         ct.attr1,
         ct.attr2
  FROM crosstab(
    '
      SELECT entity, attribute, value
      FROM eav_table
      ORDER BY 1
    '::text,
    '
      VALUES (''{0}''), (''{1}'')
    '::text
    )
  AS ct(id text,
        {0} text,
        {1} text
    );
""".format("attr1", "attr2")

しかし、入力が実行されるため、これは非常に安全ではないことを私は知っています。

私はこのような準備されたステートメントを使おうとしました:

CREATE OR REPLACE VIEW pivot_eav AS 
  SELECT ct.id,
         ct.attr1,
         ct.attr2
  FROM crosstab(
    '
      SELECT entity, attribute, value
      FROM eav_table
      ORDER BY 1
    '::text,
    '
      VALUES (''$1''), (''$2'')
    '::text
    )
  AS ct(id text,
        $1 text,
        $2 text
    );

これは合法ではないようです。

ドル記号のエスケープを使用して、最初のプレースホルダーを回避することができましたが、それでも2番目のオカレンスはそれらの位置では合法ではないようです!?

名前がリテラルとして使用されているため、その場所でドルエスケープを使用することもできませんでした。

私の質問:
プリペアドステートメントのプレースホルダーは特別な用途しかありません。 (プログラミング言語の文字列補間など、任意の位置で使用できます。)
もしそうなら、その声明をまとめる別の安全な方法はありますか?

ロビン

3
Robin Koch

CREATEステートメントを含むDDLクエリは準備できません。

また、作成可能なDMLクエリであっても、識別子にパラメータを使用することはできません。リテラルが許可されるクエリ内の場所で許可されます。

別の方法として、PL/Pythonが動的SQLに提供する専用関数を使用して、列名をクエリに安全に挿入できます。plpy.quote_ident(string)

https://www.postgresql.org/docs/current/static/plpython-util.html

2
Daniel Vérité