加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

postgresql – 当日期无效时引发错误

发布时间:2020-12-13 16:07:53 所属栏目:百科 来源:网络整理
导读:我想要做的是在日期超出支持范围的情况下提高超出范围的错误,例如类型转换. 我在CentOS上使用PostgreSQL-9.1.6.问题如下…… postgres=# select to_date('20130229','yyyymmdd'); to_date ------------ 2013-03-01(1 row) 但我想看到的输出是: postgres=# s
我想要做的是在日期超出支持范围的情况下提高超出范围的错误,例如类型转换.

我在CentOS上使用PostgreSQL-9.1.6.问题如下……

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

但我想看到的输出是:

postgres=# select '20130229'::date;
ERROR:  date/time field value out of range: "20130229"

浏览网页我发现an informative page.所以我确实将IS_VALID_JULIAN添加到to_date的函数体中,将下面标记的四行添加到formatting.c:

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;

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

+       if (!IS_VALID_JULIAN(tm.tm_year,tm.tm_mon,tm.tm_mday))
+       ereport(ERROR,+               (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),+                errmsg("date out of range: "%s"",text_to_cstring(date_txt))));

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

   PG_RETURN_DATEADT(result);
}

然后我重建了PostgreSQL:

pg_ctl -m fast stop                       # 1. stopping pgsql
vi src/backend/utils/adt/formatting.c     # 2. using the version above
rm -rf /usr/local/pgsql/*                 # 3. getting rid of all bin files
./configure --prefix=/usr/local/pgsql 
  --enable-nls --with-perl --with-libxml
  --with-pam --with-openssl
make && make install                      # 4. rebuilding source    
pg_ctl start                              # 5. starting the engine

我的bin目录信息如下.

[/home/postgres]echo $PATH
/usr/lib64/qt-3.3/bin:
/usr/local/bin:
/bin:
/usr/bin:
/usr/local/sbin:
/usr/sbin:
/sbin:
/home/postgres/bin:
/usr/bin:
/usr/local/pgsql/bin:
/usr/local/pgpool/bin:
/usr/local/pgtop/bin/pg_top:

[/home/postgres]which pg_ctl
/usr/local/pgsql/bin/pg_ctl

[/home/postgres]which postgres
/usr/local/pgsql/bin/postgres

[/usr/local/bin]which psql
/usr/local/pgsql/bin/psql

但在再次检查to_date后,结果仍然相同.

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

我错过了什么吗?

解决方法

您可以编写自己的to_date()函数,但必须使用其模式限定名称来调用它. (我使用了“公共”模式,但没有什么特别之处.)

create or replace function public.to_date(any_date text,format_string text)
returns date as
$$
select to_date((any_date::date)::text,format_string);
$$
language sql

使用裸函数名称执行本机to_date()函数.

select to_date('20130229','yyyymmdd');
2013-03-01

使用模式限定名称执行用户定义的函数.

select public.to_date('20130229','yyyymmdd');
ERROR: date/time field value out of range: "20130229"
SQL state: 22008

我知道这不是你想要的.但是. . .

>它比从源重建PostgreSQL更简单.
>修复现有的SQL和PLPGSQL源代码是一个简单的搜索和替换流编辑器.我很确定不会出错,只要你真的希望每次使用原生的to_date()都是public.to_date().
>本机to_date()函数仍将按设计工作.扩展和其他代码可能依赖于它的某种特殊行为.在更改本机函数的行为之前,请仔细考虑.

但是,需要审查新的SQL和PLPGSQL.我不希望开发人员每次都记得写public.to_date().如果使用版本控制,则可以编写预先提交挂钩以确保仅使用public.to_date().

本机to_date()函数具有我没有看到记录的行为.您不仅可以在2月29日拨打电话,也可以在2月345日或9999年2月拨打电话.

select to_date('201302345','yyyymmdd');
2014-01-11

select to_date('2013029999','yyyymmdd');
2040-06-17

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读