tom*_*mka 5 postgresql syntax datatypes plpgsql regclass
我想通过在现有表名的基础上附加后缀来创建一个新表名。Postgres 9.5 PL/pgSQL 函数获取作为regclass
类型传入的现有表名,并以字符串形式返回新名称。我format()
用来构造新名称,通常会使用%I
占位符。只要传入的表名不匹配任何 PL/pgSQL 关键字,这就会起作用。在这种情况下,无论我选择(%I
或%s
)什么类型的组件,引用都是错误的。
考虑以下函数:
CREATE OR REPLACE FUNCTION make_name(old_name regclass)
RETURNS text
LANGUAGE plpgsql AS
$$
BEGIN
RETURN format('%I_new', old_name);
END;
$$;
Run Code Online (Sandbox Code Playgroud)
进一步假设有两个表:treenode
和overlay
。为这两个函数调用此函数会产生以下新名称:
SELECT make_name('overlay'::regclass);
make_name
-------------------
"""overlay"""_new
(1 row)
SELECT make_name('treenode'::regclass);
make_name
--------------
treenode_new
(1 row)
Run Code Online (Sandbox Code Playgroud)
事实证明overlay
它也是一个 PL/pgSQL 函数(就像format
,但treenode
不是),它似乎改变了引用行为。如果%s
与 一起使用format()
,结果将是"overlay"_new
。当我使用||
运算符时也会发生同样的情况。如果我使用text
作为输入参数类型,一切都按预期工作,但我更喜欢使用regclass
.
有没有办法用不带引号的关键字匹配regclass
表名(例如overlay
)来格式化字符串,就像非关键字匹配regclass
表名(例如treenode
)的情况一样?
我将一一解决多层误解 - 得出一个简单、安全的解决方案。
0.overlay
被引用的原因不是因为它是一个函数名,而是因为它是一个保留字。
此外,overlay()
它不是“PL/pgSQL 函数”(也不是 PL/pgSQL 关键字),它是 Postgres 核心中内置的标准 SQL 函数(LANGUAGE internal
因此是幕后的 C)。事实上,PL/pgSQL 与这些都无关。
一个简单的逻辑错误。
format('%I_new', old_name)
Run Code Online (Sandbox Code Playgroud)
这将在附加'_new'之前使用双引号转义任何非标准标识符,并且即使text
作为输入类型也会失败。在引用全部内容之前,您必须附加“_new”:
format('%I', old_name || '_new')
Run Code Online (Sandbox Code Playgroud)
但这仍然不适用于regclass
. 继续阅读。
用 为regclass
变量添加引号是无稽之谈%I
,因为它的文本表示已经在需要的地方自动引用了。(类似于quote_ident()
,但不能为 NULL;因为输入是regclass
它不能为 NULL 开始。)您将应用它两次。始终%s
用于regclass
输入(字符串原样)。
format()
是矫枉过正。只需使用quote_ident()
:
quote_ident(old_name || '_new')
Run Code Online (Sandbox Code Playgroud)
4.
最重要的是,如上所述,变量的text
表示regclass
会自动转义。这是演员阵容中内置的。要获取原始文本,请直接从系统目录中pg_class
检索它。一个regclass
值只是oid
这个表的内部。
SELECT relname FROM pg_class WHERE oid = $1;
Run Code Online (Sandbox Code Playgroud)
这可以满足您的要求:
CREATE OR REPLACE FUNCTION make_name(old_name regclass)
RETURNS text AS
$func$
SELECT quote_ident(relname || '_new') FROM pg_class WHERE oid = $1;
$func$ LANGUAGE sql STABLE;
Run Code Online (Sandbox Code Playgroud)
CREATE TEMP TABLE "sUICiDAL' namE"();
CREATE TEMP TABLE overlay();
SELECT make_name('overlay') AS n1
, make_name('"sUICiDAL'' namE"') AS n2;
n1 | n2
-------------+----------------------
overlay_new | "sUICiDAL' namE_new"
Run Code Online (Sandbox Code Playgroud)
请注意,这overlay_new
是一个完全合法的标识符,因此没有被引用。
如果您希望名称未转义(无双引号),请使用:
SELECT relname || '_new' FROM pg_class WHERE oid = $1;
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
2087 次 |
最近记录: |