输入日期验证检查调用to_date

时间:2013-07-11 04:57:57

标签: postgresql date

我在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');

     

错误:时间戳超出范围

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

最后,我达成了另一个结论。以下是我的 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 效果很好,但我不确定这是否完美。我担心意外的结果,例如在有效日期投掷错误。

非常感谢任何建议。

1 个答案:

答案 0 :(得分:2)

您是否必须通过修补服务器代码来执行此操作?特别是当该补丁可能会破坏当前正在运行的SQL并且在更新PostgreSQL时需要更新?这也是一个坏主意,因为你习惯于期望to_date以你的自定义to_date的工作方式工作,当你使用未修补的PostgreSQL时,事情将会横向发展。你可能想要考虑到其他人也无法使用你的自定义PostgreSQL服务器,他们怎么知道to_date真的不是to_date而是一些修改过的版本? OTOH,也许你是为了工作保障而这样做。

为什么不编写自己的to_date替换函数,称为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'以来,您有例外。把它包裹在一个函数中并简单地说明你为什么要这样做,每个人都应该感到高兴。