Я использую postgreSQL-9.1.6 на CENTOS.

У меня проблема с функцией to_date , например ...

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

Поэтому я пытаюсь добавить проверку на выход за пределы допустимой даты.

postgres = # выберите to_date ('20130229', 'ггггммдд');

ОШИБКА: отметка времени вне допустимого диапазона

Я нашел подсказку от здесь, но это не сработало, и я спросил здесь. к сожалению, я не получил ответа.

Наконец, я пришел к другому выводу. Ниже находится My 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
KIM 11 Июл 2013 в 08:57

1 ответ

Лучший ответ

Вы должны сделать это путем исправления кода сервера? Особенно, если этот патч, вероятно, нарушит работающий в настоящее время 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_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' у вас есть исключение. Оберните это функцией и сделайте небольшой комментарий о том, почему вы это делаете, и все должны быть счастливы.

2
mu is too short 11 Июл 2013 в 09:29
Спасибо за ваш совет. create strict_to_date было бы лучше, еще один момент - проверка моей даты. Мой formatting.c НЕ ДОЛЖЕН генерировать исключение для действительной даты.
 – 
KIM
11 Июл 2013 в 10:00
Какая часть вашей проверки даты не будет покрыта поездкой туда и обратно to_date - to_char? Я не думаю, что проверка строки отклонит какие-либо действительные даты.
 – 
mu is too short
11 Июл 2013 в 10:23