以下の例で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の場合です。
ターゲットテーブル名のあいまいさを回避するために、スキーマとテーブルの名前を別々に指定してください。 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');
関連:
テーブルLIKE
別のテーブルを再作成する場合に問題が発生します。なぜそれが良い考えになるのか、私にはわかりません。通常、私がこの種のものを見たとき、それは multi-tenant ソリューションを作成する試みです。あなたは間違った方向に進んでいると思います。まったく異なる提案として、 行レベルのセキュリティ を確認してください。ユーザーがマスターテーブルのコピーを持っていることを確認する必要がある場合は、単にマスターテーブルを使用することをお勧めします。
また、別のテーブルをDROP IF EXISTS
だけにするのが常識であるかどうかもわかりません。そのテーブルが一時的な一時テーブルである場合は、CREATE TEMPORARY TABLE
を調べる必要があります-次に、接続を解除し、必要に応じて再作成するだけです(CREATE TEMPORARY TABLE IF NOT EXISTS
)。
とにかく、私は推測しているだけです。より適切な回答を得るために、別の質問で詳細を提供できます。