我创建了一个自定义类型
CREATE TYPE rc_test_type AS (a1 bigint);
和一个函数
CREATE OR REPLACE FUNCTION public.rc_test_type_function(test_table character varying, dummy integer)
RETURNS rc_test_type AS
$BODY$
DECLARE
ret rc_test_type;
query text;
BEGIN
query := 'SELECT count(*) from ' || test_table ;
EXECUTE query into ret.a1;
RETURN ret;
END $BODY$
LANGUAGE plpgsql VOLATILE
如果我跑
SELECT * FROM rc_test_type_function('some_table', 1);
我明白了
"a1"
1389
到目前为止一切顺利。
如果我跑
SELECT p FROM (SELECT rc_test_type_function('some_table', s.step) AS p
FROM some_other_table s) foo;
我明白了
"p"
"(1389)"
"(1389)"
因为“some_other_table”只有两条记录。很好。
但是如果我尝试
SELECT p.a1 FROM (select rc_test_type_function('some_table', s.step) AS p
FROM some_other_table s) foo;
我得到了错误
missing FROM-clause entry in subquery for table »p«
我觉得这很奇怪,因为子查询没有改变。
两个问题:
- 谁能解释一下这是怎么回事?
- 如何从返回的数组中提取字段值
a1
?
最佳答案
在复合类型两边使用括号:
SELECT <b>(</b>p<b>)</b>.a1
FROM (SELECT rc_test_type_function('some_table', s.step) AS p
FROM some_other_table s
) foo;
即使您的类型只有一列,它仍然是复合类型 - 具有自己的列名。没有多大意义,但这就是您构建它的方式。
(您可能只想使用简单类型或 DOMAIN
代替。)
引用 the manual here :
(compositecol).somefield
(mytable.compositecol).somefield
The parentheses are required here to show that
compositecol
is a column name not a a table name, or thatmytable
is a table name not a schema name in the second case.
适当的功能
省略复合类型的部分,这样你的函数将更安全、更简单、更快:
CREATE OR REPLACE FUNCTION foo(test_table varchar, dummy int, OUT p bigint)
AS
$func$
BEGIN
EXECUTE format('SELECT count(*) from %I', test_table) -- !avoid SQLi!
INTO p;
END
$func$ LANGUAGE plpgsql;
- 使用动态 SQL 避免 SQL 注入(inject)!
- 安
OUT
parameter在这种情况下简化语法。您根本不需要DECLARE
子句,也不需要RETURN
更好
CREATE OR REPLACE FUNCTION foo(test_table regclass, dummy int, OUT p bigint)
AS
$func$
BEGIN
EXECUTE 'SELECT count(*) from ' || test_table
INTO p;
END
$func$ LANGUAGE plpgsql;
- 通过使用 object identifier
regclass
这也适用于模式限定的表名。 SQLi 是不可能的。如果表名不合法,该函数将立即失败,并在自动转换为text
时自动引用。
关于postgresql - 从函数返回的自定义类型的意外行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15924900/