tin*_*lyx 5 postgresql dynamic-sql plpgsql postgresql-10
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;
Run Code Online (Sandbox Code Playgroud)
我的困境是我想引用输入表名称_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)
Run Code Online (Sandbox Code Playgroud)
这是 PostgreSQL 10.3 的情况。
为避免目标表名称含糊不清,请分别提供架构名称和表名称。对于现有表,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;
Run Code Online (Sandbox Code Playgroud)
称呼:
SELECT copy_table('ex.test', 'text1', 'ex');
Run Code Online (Sandbox Code Playgroud)
由于第三个(最后一个)参数_target_schema
有默认值,我们可以省略它,在这种情况下,函数默认为源表的架构:
SELECT copy_table('ex.test', 'test1');
Run Code Online (Sandbox Code Playgroud)
即使我们没有明确提供源模式,也依赖于当前的search_path
:
SELECT copy_table('test', 'test1');
Run Code Online (Sandbox Code Playgroud)
有关的: