0

我在 CENTOS 上使用 postgreSQL-9.1.6。

我在to_date函数上有问题,比如......

postgres=# select to_date('20130229','yyyymmdd');
  to_date   
------------
 2013-03-01
(1 row)

所以我正在尝试针对传入日期添加超出范围的验证检查。

postgres=#select to_date('20130229','yyyymmdd');

错误:时间戳超出范围

我从这里找到了一个提示,但它没有用,我在这里问。不幸的是,我无法得到答案。

最后,我得出了另一个结论。下面是我的formatting.c,其中添加了9行标记+

Datum
to_date(PG_FUNCTION_ARGS)
{
        text       *date_txt = PG_GETARG_TEXT_P(0);
        text       *fmt = PG_GETARG_TEXT_P(1);
        DateADT         result;
        struct pg_tm tm;
        fsec_t          fsec;

    +   int ndays[]={-1,31,28,31,30,31,30,31,31,30,31,30,31};

    +   int last_day_of_month;

        do_to_timestamp(date_txt, fmt, &tm, &fsec);

    +   last_day_of_month = ndays[tm.tm_mon];
    +   if (((tm.tm_year & 3) == 0 && ((tm.tm_year % 25) != 0 || (tm.tm_year & 15) == 0)) && tm.tm_mon == 2 )
    +           last_day_of_month = ndays[tm.tm_mon] + 1;

    +   if( tm.tm_mon > 12 || tm.tm_mon < 1 || tm.tm_mday > last_day_of_month || tm.tm_mday < 1
)
    +           ereport(ERROR,
    +                           (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    +                            errmsg("timestamp out of range")));

        result = date2j(tm.tm_year, tm.tm_mon, tm.tm_mday) - POSTGRES_EPOCH_JDATE;

        PG_RETURN_DATEADT(result);
}

虽然我自己的formatting.c效果很好,但我不确定它是否完美。我担心会出现意外结果,例如针对有效日期抛出错误。

任何建议将不胜感激。

4

1 回答 1

2

您必须通过修补服务器代码来做到这一点吗?特别是当该补丁可能会破坏当前工作的 SQL 并且需要在更新 PostgreSQL 时进行更新时?这也是一个坏主意,因为您会养成期望to_date按照您的自定义工作方式工作的习惯,to_date而当您使用未打补丁的 PostgreSQL 时,事情会横向发展。您可能还想考虑到其他人也被困在您的自定义 PostgreSQL 服务器上,他们应该怎么知道这to_date实际上不是to_date一些修改版本?OTOH,也许您这样做是为了工作安全。

为什么不编写自己的to_date替换函数,称为 say strict_to_date,它使用to_date然后执行简单的转换:

string = to_char(to_date_result, 'yyyymmdd')

比较?如果to_dateto_char往返没有给你原来的结果,那么你可以提出你的例外。您当然需要决定做什么strict_to_date(null),但这很容易添加。

考虑一些简单的结果:

=> select to_date('20130229','yyyymmdd');
  to_date   
------------
 2013-03-01
(1 row)

=> select to_char(to_date('20130229','yyyymmdd'), 'yyyymmdd');
 to_char  
----------
 20130301
(1 row)

既然'20130229' != '20130301'你有你的例外。将其包装在一个函数中,并添加一些关于您为什么要这样做的评论,每个人都应该感到高兴。

于 2013-07-11T05:29:30.030 回答