PL / pgSQL函数中的自定义类型,模式范围漏洞? (postgres的)

时间:2018-01-25 04:10:42

标签: postgresql

无论好坏,我都有以下自定义类型和聚合。

create type nanotime as (
  seconds bigint,
  nanos int
);

create function nanotime_max_sfunc(current_max nanotime, candidate nanotime)
returns nanotime
immutable
language plpgsql
as $$
declare
  result nanotime;
begin
  if (current_max.seconds > candidate.seconds) or
     (current_max.seconds = candidate.seconds and current_max.nanos > candidate.nanos) then
    result := current_max;
  else 
    result := candidate;
  end if;
  return result;
end;
$$;

create aggregate max_nanotime(nanotime) (
  sfunc = nanotime_max_sfunc,
  stype = nanotime
);

这些都驻留在time架构中。我使用flyway迁移这个数据库。当我在flyway迁移中select max_nanotime(my_nanotime_column) - 在time模式的上下文中执行时 - 它工作正常。但是当我从select time.max_nanotime(my_nanotime_column)架构的上下文之外执行time时,我得到以下内容:

ERROR:  type "nanotime" does not exist
LINE 3:   result nanotime;
                 ^
QUERY:  
declare
  result nanotime;
begin
  if (current_max.seconds > candidate.seconds) or
     (current_max.seconds = candidate.seconds and current_max.nanos > candidate.nanos) then
    result := current_max;
  else 
    result := candidate;
  end if;
  return result;
end;

CONTEXT:  compilation of PL/pgSQL function "nanotime_max_sfunc" near line 3

在我看来,函数nanotime_max_sfunc没有保留它创建的范围。这很奇怪,因为聚合max_nanotime确实保留了它创建的范围。我的猜测是聚合,以声明方式定义,不需要编译,并在声明时完全形成。另一方面,命令性地定义的函数在使用时被编译,允许它们在不同模式的上下文中具有不同的行为。

这让我觉得非常奇怪。我的评估准确吗?如何从nanotime明确引用nanotime_max_sfunc

2 个答案:

答案 0 :(得分:1)

目前尚不清楚在时间架构的上下文中执行的含义,但我将向您解释架构解析在函数上下文中的工作原理。那么也许你可以弄清楚你的情况会发生什么。

当首次在会话中执行PL / pgSQL函数时,会计划其查询并将计划缓存到会话结束或者直到发生导致计划失效的情况。

计划SQL语句时,将使用当前设置SET解析所有非模式限定的名称。

为了避免像您描述的那样的问题,最好使用CREATE FUNCTION的{​​{1}}子句来修复search_path的值以执行函数(即使运算符在模式中也是如此在PostgreSQL中,因此很难对你的函数中的所有内容进行模式限定。)

答案 1 :(得分:0)

感谢Laurenz Albe! search_path记录在https://www.postgresql.org/docs/9.3/static/sql-createfunction.html下标题为'安全编写安全定义函数'的标题下。我的结果代码,带有更改注释,是:

create type nanotime as (
  seconds bigint,
  nanos int
);

create function time.nanotime_max_sfunc(current_max nanotime, candidate nanotime)
returns nanotime
immutable
language plpgsql
set search_path to time   -- <---------------- CHANGE
as $$
declare
  result nanotime;
begin
  if (current_max.seconds > candidate.seconds) or
     (current_max.seconds = candidate.seconds and current_max.nanos > candidate.nanos) then
    result := current_max;
  else 
    result := candidate;
  end if;
  return result;
end;
$$;

create aggregate max_nanotime(nanotime) (
  sfunc = nanotime_max_sfunc,
  stype = nanotime
);

听起来有这样的安全后果,所以我打算详细阅读文档的这一部分。

再次感谢Laurenz Albe。