函数调用的属性表示法给出错误

Posted

技术标签:

【中文标题】函数调用的属性表示法给出错误【英文标题】:Attribute notation for function call gives error 【发布时间】:2019-06-29 09:23:02 【问题描述】:

当当前模式与函数之一不同时,属性表示法函数调用会出错。

我已经创建了一个函数

CREATE FUNCTION pub.FullName(pub.reps)
  RETURNS text AS
$func$
       select ($1.fname || ' ' || $1.lname)
$func$ LANGUAGE SQL;

我正在尝试使用docs 中所述的属性表示法调用函数:

select r.fullname from pub.reps r;

但是得到一个错误信息:

ERROR:  column "fullname" does not exist

使用功能符号查询可以正常工作:

select pub.fullname(r.*) from pub.reps r;

数据库已通过备份/恢复从 PostgreSQL 10 迁移。

Select version() 给出:PostgreSQL 11.3, compiled by Visual C++ build 1914, 64-bit

UPD。发现如果我将pub 模式设置为默认值,那么select r.fullname from pub.reps r 可以正常工作。

【问题讨论】:

测试数据库在哪个服务器上?为什么混合大小写?你在任何地方都使用过双引号吗? 混合大小写仅是为了便于阅读。它不影响结果。服务器与第一个数据库相同 - 我自己的笔记本电脑。 我发现它取决于当前架构。如果我将 pub 模式设置为默认值,那么 select r.FullName from pub.reps r 可以工作。否则我会得到一个错误。 @ErwinBrandstetter,感谢您的详细回答和改进我的帖子。现在看起来好多了。也适用于 dbfiddle 链接。这应该是一个很好的工具。据我了解,如果不修改搜索路径(例如在查询中显式使用模式),就无法使用属性功能。所以我最好等 Postgres 12。 函数的模式必须在搜索路径中,因为无法对属性进行模式限定(变成函数)。严格来说,您没有必须修改search_path:您始终可以在已经存在的架构中创建函数,pg_catalog 作为最后的措施。 (虽然我宁愿避免将用户对象放在那里。) 【参考方案1】:

你自己找到了问题的根源。准确地说:函数pub 的架构必须在当前search_path任何地方列出,不必是“默认”或“当前” " 架构(列表中的第一个)。相关:

How does the search_path influence identifier resolution and the "current schema"

所以 Postgres 没有找到这个函数。在这方面,Postgres 11 与 Postgres 10 没有什么不同。不过,有一些值得注意的相关发展。你提到:

数据库已通过备份/恢复从 PostgreSQL 10 迁移。

考虑一下release notes for Postgres 11 中指出的这种细微变化:

在区分函数与列引用时考虑句法形式 (Tom Lane)

x 是表名或复合列时,PostgreSQL 有 传统上认为句法形式 f(x)x.f 是 等效的,允许使用诸如编写函数然后使用之类的技巧 就好像它是一个按需计算的列。但是,如果两者 解释是可行的,列解释总是 如果用户想要 功能解释。现在,如果有歧义, 选择符合句法形式的解释。

所以,如果在表reps 中有一个列fullname 还有你显示的函数pub.fullname(pub.reps),P​​ostgres 10,即使使用功能符号,仍然会选择

SELECT fullname(r) FROM reps r;  -- resolves to column if it exists, ignoring function

dbfiddle here 用于 Postgres 10

Postgres 11(更合理)选择函数:

dbfiddle here 用于 Postgres 11

Postgres 12(目前为测试版)最终实​​现了真正的生成列。 The release notes:

添加对生成列的支持 (Peter Eisentraut)

生成的列的内容是根据表达式计算的 (包括对同一表中其他列的引用)而不是 由INSERTUPDATE 命令指定。

不过,只有 STORED 生成的列进入了这个版本。 (更有趣的 IMO)VIRTUAL variant was postponed for a later release。 (还没有在 Postgres 13 中。)

您的表格可能如下所示:

CREATE TABLE pub.reps (
  reps_id  int GENERATED ALWAYS AS IDENTITY PRIMARY KEY 
, fname    text NOT NULL
, lname    text NOT NULL
, fullname text GENERATED ALWAYS AS (fname || ' ' || lname) STORED
);

db小提琴here

我声明了fnamelnameNOT NULL。否则,您的简单串联 (fname || ' ' || lname) 是一个陷阱。见:

How to concatenate columns in a Postgres SELECT? Combine two columns and add into one new column

【讨论】:

以上是关于函数调用的属性表示法给出错误的主要内容,如果未能解决你的问题,请参考以下文章

在新实例中重新定义类属性(在getter函数调用之前)失败

函数属性,方法和构造函数

声纳给出“预期分配或函数调用”消息

80x86调用函数指令是啥

OCUnit 测试在未测试的类中给出错误

纯虚函数调用