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 次 |
| 最近记录: |