postgresql - 从函数返回的自定义类型的意外行为

标签 postgresql syntax types plpgsql postgresql-9.2

我创建了一个自定义类型

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«

我觉得这很奇怪,因为子查询没有改变。

两个问题:

  1. 谁能解释一下这是怎么回事?
  2. 如何从返回的数组中提取字段值 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 that mytable 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/

相关文章:

python - 将数据从 MySQL 数据库移植到 PostgreSQL

postgresql - 在 OpenSuse 13.2 上为 PostgreSQL 9.4.1 构建 PL/Java

javascript - 在 JavaScript 中,是否有任何方法可以在不使用点符号或方括号符号的情况下获取对象的属性?

mysql - 如何选择SQL数据库表中的第n行?

ruby-on-rails - Rails 行为不当 wrt Postgres SERIAL NOT NULL 专栏

c# - 声明局部变量

php - 使用截断表,没有结果

python3 : singledispatch in class, 如何分派(dispatch)自身类型

javascript - 是否需要初始化在 Javascript 中作为 "class"构造函数参数传递的变量?

c - 在 c 中传递 typedef 枚举作为参数会引发错误