在相关函数调用中保留 PostgreSQL 架构标识符
Preserve PostgreSQL schema identifier in dependent function calls
我有一个存储过程 RETURNS record
:
CREATE OR REPLACE FUNCTION r_rpt_prov_summary()
RETURNS record
AS $$
DECLARE
_fields record;
BEGIN
SELECT INTO _fields
0::integer AS customers,
0::integer AS customers_active;
SELECT INTO _fields.customers count(*) FROM customer;
SELECT INTO _fields.customers_active count(*) FROM customer WHERE active = 't';
RETURN _fields;
END
$$ LANGUAGE 'plpgsql';
但是,为了查询它,我必须明确枚举返回的列和类型:
SELECT * FROM r_rpt_prov_summary() AS (a integer, b integer);
为了使其适合 MVC 框架,其本质上想要查询表,我将其包装在 SQL
函数中 RETURNS TABLE
:
CREATE OR REPLACE FUNCTION rpt_prov_summary()
RETURNS TABLE (
customers integer,
customers_active integer
) AS $$
SELECT * FROM r_rpt_prov_summary() AS (customers integer, customers_active integer);
$$ LANGUAGE 'sql';
只要两个函数驻留在相同的模式或 search_path
space 中,这就非常有效。但是,在这种情况下,它们存在于自己的非标准模式中,因此我必须将外部函数查询为 myschema.rpt_prov_summary()
,即
SELECT * FROM myschema.rpt_prov_summary();
如果我的架构和搜索路径设置为 public
:
,这将不起作用
test=> SELECT * FROM myschema.rpt_prov_summary();
ERROR: function r_rpt_prov_summary() does not exist
LINE 2: SELECT * FROM r_rpt_prov_summary() AS (customers integer, ...
^
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
自然地,您的想法会转向在查询执行之前调用 SET SCHEMA 'myschema'
或 SET search_path TO myschema
。我的也是。问题是它不适用于我调用的环境。 MVC 框架使用准备好的语句来构造查询,而 PostgreSQL 不赞成这样的事情:
SET search_path TO myschema;SELECT * FROM rpt_prov_summary();
也就是说:
< 2016-03-14 20:50:46.410 EDT >ERROR: cannot insert multiple commands into a prepared statement
所以,那是行不通的。将模式作为参数提供给外部函数也行不通;我只是在 MVC 框架的约束下没有这种灵活性,它想要查询普通的旧表或像表一样的东西。
current_schema
标识客户端会话的当前架构,因此这不会有帮助。已经试过了:
CREATE OR REPLACE FUNCTION rpt_prov_summary()
RETURNS TABLE (
customers integer,
customers_active integer
) AS $$
BEGIN
RAISE NOTICE 'Current schema: %', current_schema;
RETURN QUERY EXECUTE 'SELECT * FROM ' || current_schema || '.r_rpt_prov_summary() AS (customers integer, customers_active integer)';
END
$$ LANGUAGE 'plpgsql';
没有骰子 - Current schema: public
,如预期。
有没有办法以某种方式捕获外部调用的架构 space 并将其传播到封装的查询中?
1.
I have a stored procedure ...
不,你不知道。你有一个功能,它几乎但不完全相同。 Postgres 目前不支持存储过程。
2.
彻底简化。使用一个带有 OUT
参数的简单 SQL 函数,而不是两个嵌套函数:
CREATE OR REPLACE FUNCTION myschema.r_rpt_prov_summary( -- schema-qualify!
OUT _customers integer
, OUT _customers_active integer) AS
$func$
SELECT count(*)::int
, count(*) FILTER (WHERE active)::int -- requires Postgres 9.4+
FROM myschema.customer; -- schema-qualify!
$func$ LANGUAGE sql; -- don't quote the language name
致电:
SELECT * FROM myschema.rpt_prov_summary();
独立于您当前的 search_path
设置工作。
注意RETURNS TABLE()
和RETURNS record
之间的细微差别(我的版本也是RETURNS record
,但我在声明OUT参数后没有明确指定!):后面总是returns 恰好 1 行(Postgres 知道并可以依赖它),而前者可以 return 0 - n 行.
3.
您 可以 以多种不同方式设置 search_path
,甚至可以作为函数本身的本地设置 - 如有必要:
- How does the search_path influence identifier resolution and the "current schema"
回答您的实际问题:
Is there any way to somehow capture the schema space of the outer call
and propagate that into the encapsulated query?
CREATE OR REPLACE FUNCTION myschema.r_rpt_prov_summary(OUT _customers integer
, OUT _customers_active integer) AS
$func$
BEGIN
SELECT INTO _customers, _customers_active
count(*)::int, count(*) FILTER (WHERE active)::int
FROM <b>customer; -- no schema-qualification</b>
END
$func$ LANGUAGE plpgsql;
CREATE OR REPLACE FUNCTION myschema.rpt_prov_summary()
RETURNS TABLE (customers int, customers_active int) AS
$func$
SELECT * FROM myschema.r_rpt_prov_summary();
$func$ LANGUAGE sql <b>SET search_path = myschema</b>; -- set the search_path here
search_path
传播到嵌套函数 - 正是您要找的。
或者只是模式限定标识符无处不在(包括函数名称)是明确的。
我有一个存储过程 RETURNS record
:
CREATE OR REPLACE FUNCTION r_rpt_prov_summary()
RETURNS record
AS $$
DECLARE
_fields record;
BEGIN
SELECT INTO _fields
0::integer AS customers,
0::integer AS customers_active;
SELECT INTO _fields.customers count(*) FROM customer;
SELECT INTO _fields.customers_active count(*) FROM customer WHERE active = 't';
RETURN _fields;
END
$$ LANGUAGE 'plpgsql';
但是,为了查询它,我必须明确枚举返回的列和类型:
SELECT * FROM r_rpt_prov_summary() AS (a integer, b integer);
为了使其适合 MVC 框架,其本质上想要查询表,我将其包装在 SQL
函数中 RETURNS TABLE
:
CREATE OR REPLACE FUNCTION rpt_prov_summary()
RETURNS TABLE (
customers integer,
customers_active integer
) AS $$
SELECT * FROM r_rpt_prov_summary() AS (customers integer, customers_active integer);
$$ LANGUAGE 'sql';
只要两个函数驻留在相同的模式或 search_path
space 中,这就非常有效。但是,在这种情况下,它们存在于自己的非标准模式中,因此我必须将外部函数查询为 myschema.rpt_prov_summary()
,即
SELECT * FROM myschema.rpt_prov_summary();
如果我的架构和搜索路径设置为 public
:
test=> SELECT * FROM myschema.rpt_prov_summary();
ERROR: function r_rpt_prov_summary() does not exist
LINE 2: SELECT * FROM r_rpt_prov_summary() AS (customers integer, ...
^
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
自然地,您的想法会转向在查询执行之前调用 SET SCHEMA 'myschema'
或 SET search_path TO myschema
。我的也是。问题是它不适用于我调用的环境。 MVC 框架使用准备好的语句来构造查询,而 PostgreSQL 不赞成这样的事情:
SET search_path TO myschema;SELECT * FROM rpt_prov_summary();
也就是说:
< 2016-03-14 20:50:46.410 EDT >ERROR: cannot insert multiple commands into a prepared statement
所以,那是行不通的。将模式作为参数提供给外部函数也行不通;我只是在 MVC 框架的约束下没有这种灵活性,它想要查询普通的旧表或像表一样的东西。
current_schema
标识客户端会话的当前架构,因此这不会有帮助。已经试过了:
CREATE OR REPLACE FUNCTION rpt_prov_summary()
RETURNS TABLE (
customers integer,
customers_active integer
) AS $$
BEGIN
RAISE NOTICE 'Current schema: %', current_schema;
RETURN QUERY EXECUTE 'SELECT * FROM ' || current_schema || '.r_rpt_prov_summary() AS (customers integer, customers_active integer)';
END
$$ LANGUAGE 'plpgsql';
没有骰子 - Current schema: public
,如预期。
有没有办法以某种方式捕获外部调用的架构 space 并将其传播到封装的查询中?
1.
I have a stored procedure ...
不,你不知道。你有一个功能,它几乎但不完全相同。 Postgres 目前不支持存储过程。
2.
彻底简化。使用一个带有 OUT
参数的简单 SQL 函数,而不是两个嵌套函数:
CREATE OR REPLACE FUNCTION myschema.r_rpt_prov_summary( -- schema-qualify!
OUT _customers integer
, OUT _customers_active integer) AS
$func$
SELECT count(*)::int
, count(*) FILTER (WHERE active)::int -- requires Postgres 9.4+
FROM myschema.customer; -- schema-qualify!
$func$ LANGUAGE sql; -- don't quote the language name
致电:
SELECT * FROM myschema.rpt_prov_summary();
独立于您当前的 search_path
设置工作。
注意RETURNS TABLE()
和RETURNS record
之间的细微差别(我的版本也是RETURNS record
,但我在声明OUT参数后没有明确指定!):后面总是returns 恰好 1 行(Postgres 知道并可以依赖它),而前者可以 return 0 - n 行.
3.
您 可以 以多种不同方式设置 search_path
,甚至可以作为函数本身的本地设置 - 如有必要:
- How does the search_path influence identifier resolution and the "current schema"
回答您的实际问题:
Is there any way to somehow capture the schema space of the outer call and propagate that into the encapsulated query?
CREATE OR REPLACE FUNCTION myschema.r_rpt_prov_summary(OUT _customers integer
, OUT _customers_active integer) AS
$func$
BEGIN
SELECT INTO _customers, _customers_active
count(*)::int, count(*) FILTER (WHERE active)::int
FROM <b>customer; -- no schema-qualification</b>
END
$func$ LANGUAGE plpgsql;
CREATE OR REPLACE FUNCTION myschema.rpt_prov_summary()
RETURNS TABLE (customers int, customers_active int) AS
$func$
SELECT * FROM myschema.r_rpt_prov_summary();
$func$ LANGUAGE sql <b>SET search_path = myschema</b>; -- set the search_path here
search_path
传播到嵌套函数 - 正是您要找的。
或者只是模式限定标识符无处不在(包括函数名称)是明确的。