web-dev-qa-db-ja.com

format()関数で修飾テーブル名を引用する方法は?

以下の例でformat関数を使用してテーブル名を適切に引用するのにいくつか問題があります。

CREATE OR REPLACE FUNCTION copy_table(_source_tbl regclass, _target_tbl text)
 RETURNS bool AS $func$
DECLARE query_str text; 
BEGIN
  query_str = format($fmt$ DROP TABLE IF EXISTS %1$I; CREATE TABLE %1$I AS (TABLE %s); $fmt$, _target_tbl, _source_tbl);
  EXECUTE query_str;
  RAISE NOTICE '%', query_str;
 RETURN True;
END $func$ LANGUAGE plpgsql;

私のジレンマは、入力テーブル名を引用したいということです_target_tbl識別子として(SQLインジェクションを回避するため)。ただし、完全なテーブル名ex.test1、これによりスキーマ部分ex.テーブル名とテーブルの一部として扱われるpublic."ex.test1"デフォルトで作成public.スキーマを以下に示します。

ここで識別子を適切に引用/フォーマットする必要がありますか?

=> SELECT copy_table('ex.test', 'ex.test1');
NOTICE:  table "ex.test1" does not exist, skipping
NOTICE:   DROP TABLE IF EXISTS "ex.test1"; CREATE TABLE "ex.test1" AS (TABLE ex.test);

=> \dt ex.test1
Did not find any relation named "ex.test1".
=> \dt "ex.test1"
         List of relations
 Schema |   Name   | Type  | Owner 
--------+----------+-------+-------
 public | ex.test1 | table | 
(1 row)

これはPostgreSQL 10.3の場合です。

4
tinlyx

ターゲットテーブル名のあいまいさを回避するために、スキーマとテーブルの名前を別々に指定してくださいexistingテーブルを使用すると、Postgresは現在の search_path 修飾されていないテーブル名の場合、その名前のオブジェクトを持つ最初のスキーマにデフォルト設定します。 (まだ)存在しないテーブルでは明らかにそれは不可能であるため、そこでより明示的にする必要があります。

通常、ターゲットテーブルをソースと同じスキーマに配置する場合でも、便宜上、スキーマ名を省略して、関数をデフォルトの(既存!)ソーステーブルのスキーマにすることができます。お気に入り:

CREATE OR REPLACE FUNCTION copy_table(_source_tbl regclass
                                    , _target_tbl text
                                    , _target_schema text = NULL)
  RETURNS bool AS
$func$
DECLARE
   query_str text; 
BEGIN
   IF _target_schema IS NULL THEN               -- if no target schema provided ...
      SELECT c.relnamespace::regnamespace::text -- ... default to schema of input table
      FROM   pg_class c
      WHERE  c.oid = _source_tbl
      INTO  _target_schema;
   END IF;

   query_str = format('DROP TABLE IF EXISTS %1$I.%2$I;
                       CREATE TABLE %1$I.%2$I AS (TABLE %3$s);'
    , _target_schema
    , _target_tbl
    , _source_tbl);

   EXECUTE query_str;
   RAISE NOTICE '%', query_str;
   RETURN true;
END
$func$  LANGUAGE plpgsql;

コール:

SELECT copy_table('ex.test', 'text1', 'ex');

3番目(最後)のパラメーター_target_schemaにはデフォルト値があります。省略できます。その場合、関数はデフォルトでソーステーブルのスキーマに設定されます。

SELECT copy_table('ex.test', 'test1');

ソーススキーマexplicitlyを提供しなくても、現在のsearch_path

SELECT copy_table('test', 'test1');

関連:

3

テーブルLIKE別のテーブルを再作成する場合に問題が発生します。なぜそれが良い考えになるのか、私にはわかりません。通常、私がこの種のものを見たとき、それは multi-tenant ソリューションを作成する試みです。あなたは間違った方向に進んでいると思います。まったく異なる提案として、 行レベルのセキュリティ を確認してください。ユーザーがマスターテーブルのコピーを持っていることを確認する必要がある場合は、単にマスターテーブルを使用することをお勧めします。

また、別のテーブルをDROP IF EXISTSだけにするのが常識であるかどうかもわかりません。そのテーブルが一時的な一時テーブルである場合は、CREATE TEMPORARY TABLEを調べる必要があります-次に、接続を解除し、必要に応じて再作成するだけです(CREATE TEMPORARY TABLE IF NOT EXISTS)。

とにかく、私は推測しているだけです。より適切な回答を得るために、別の質問で詳細を提供できます。

0
Evan Carroll