传递参数会在Postgres 8.2函数中产生数组错误

时间:2015-03-20 15:10:47

标签: postgresql parameters plpgsql dynamic-sql greenplum

我有这个功能

/*
@Function: valiDates [Avoid inserting data from invalid dates]
@Purpose: Providing a _TABLE and a date _COLUMN to be validated.
Given a _DATE (from script name) validate that a certain % of data (_TOLERANCE) belongs to the _INTERVAL of days specified.
*/

CREATE OR REPLACE FUNCTION valiDates(_date date, _table regclass, _column text, _interval integer,  _tolerance real) RETURNS BOOLEAN AS
$$
DECLARE result boolean;
BEGIN
    EXECUTE 'SELECT
            (SELECT count(*) FROM ' || _table::regclass || '
             WHERE ' || _column || ' BETWEEN '''|| _date || '''::date and ''' || _date || '''::date + INTERVAL ''' ||  _interval || 'days'')'
                        || '/
            (SELECT COUNT(*) FROM ' || _table::regclass || ')::real
         > ' || _tolerance
    INTO result;
    RETURN result;
END
;
$$ LANGUAGE plpgsql;

它实际上适用于我的PostgreSQL环境版本9.1.13,但是当我尝试在Dev Server(PostgreSQL 8.2)上调用此函数时,会出现以下错误:

array value must start with "{" or dimension information

它应该在官方documentation page中描述的8.2上工作。

这就是我调用函数的方式:

select valiDates('2015-03-01','_table','_date',1,0.8);

我真的不知道如何修复它,我已经尝试用'_table'::regclass调用该函数但它也不起作用。

2 个答案:

答案 0 :(得分:0)

您的错误消息很可能来自 _date 作为参数名称。 _datedate[]的别名 - 日期数组的类型名称。类似于_interval
非常古老的版本的Postgres可能会误解第一个单词_date作为数据类型而不是参数名称。使用合理的参数名称来解决此问题。使用基本类型名称作为任何类型的标识符永远是一个好主意。

您的功能已经过审核,在Postgres 8.2中工作(未经测试):

CREATE OR REPLACE FUNCTION validates(_day date, _table regclass, _column text
                                   , _days integer, _tolerance real)
  RETURNS BOOLEAN AS
$func$
DECLARE result boolean;
BEGIN
   EXECUTE 'SELECT
           (SELECT count(*) FROM ' || _table || '
            WHERE ' || quote_ident(_column) || ' BETWEEN '''
            || _day || '''::date and '''
            || _day || '''::date + ' ||  _days
            || ') >
           (SELECT COUNT(*) FROM ' || _table || ') * ' || _tolerance
   INTO result;
   RETURN result;
END
$func$ LANGUAGE plpgsql;

注意:

  • 按照讨论的方式修复参数名称。

  • 这是胡说八道:_table::regclass - _table已经是[{1}}类型

  • 另一方面,这是自杀:regclass。 SQL注入广泛开放。请改用_column

  • 您只需添加quote_ident(_column)即可添加天数。更简单。

  • date + integer可以重写为3 / 2 > 1.5。更短,更清洁,更清晰,避免舍入错误,无需演员。

现代语法

在Postgres 9.1+中,这可能是:

3 > 2 * 1.5

甚至在Postgres 9.4+中使用新的聚合CREATE OR REPLACE FUNCTION validates(_day date, _tbl regclass, _col text , _days int, _tolerance real , OUT result boolean) AS $func$ BEGIN EXECUTE format( 'SELECT count((%I BETWEEN $1 AND $2) OR NULL) > count(*) * $3 FROM %s' , _col, _tbl ) USING _day, _day + _days, _tolerance INTO result; END $func$ LANGUAGE plpgsql; 子句更清洁:

FILTER

说明:

答案 1 :(得分:0)

感谢Erwin的建议,我把大部分内容都拿走了。最后我意识到由于_table参数(regclass类型)我只需要更改它或字符串(文本),它期待一个数组。