我在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 效果很好,但我不确定这是否完美。我担心意外的结果,例如在有效日期投掷错误。
非常感谢任何建议。
答案 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_date
和to_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'
以来,您有例外。把它包裹在一个函数中并简单地说明你为什么要这样做,每个人都应该感到高兴。