On 14.08.2016 01:52, Andreas 'ads' Scherbaum wrote:
Attached is a patch to "do the right thing". The verification is in "to_date()" now, the extra function is removed. Regression tests are updated - two or three of them returned a wrong date before, and still passed. They fail now. Documentation is also updated. Regards,
Is it right and "true" way to validate date by extra transforming and comparison?
Maybe validate date by using ValidateDate(). Attached sample patch. -- Artur Zakirov Postgres Professional: http://www.postgrespro.com Russian Postgres Company
diff --git a/src/backend/utils/adt/formatting.c b/src/backend/utils/adt/formatting.c index bbd97dc..c0048c9 100644 --- a/src/backend/utils/adt/formatting.c +++ b/src/backend/utils/adt/formatting.c @@ -3563,7 +3563,9 @@ do_to_timestamp(text *date_txt, text *fmt, { FormatNode *format; TmFromChar tmfc; - int fmt_len; + int fmt_len, + fmask = 0; /* Bit mask for ValidateDate() */ + char *date_str = NULL; ZERO_tmfc(&tmfc); ZERO_tm(tm); @@ -3574,7 +3576,6 @@ do_to_timestamp(text *date_txt, text *fmt, if (fmt_len) { char *fmt_str; - char *date_str; bool incache; fmt_str = text_to_cstring(fmt); @@ -3630,7 +3631,6 @@ do_to_timestamp(text *date_txt, text *fmt, DCH_from_char(format, date_str, &tmfc); - pfree(date_str); pfree(fmt_str); if (!incache) pfree(format); @@ -3706,6 +3706,7 @@ do_to_timestamp(text *date_txt, text *fmt, if (tmfc.bc && tm->tm_year > 0) tm->tm_year = -(tm->tm_year - 1); } + fmask |= DTK_M(YEAR); } else if (tmfc.cc) /* use first year of century */ { @@ -3717,10 +3718,14 @@ do_to_timestamp(text *date_txt, text *fmt, else /* +1 because year == 599 is 600 BC */ tm->tm_year = tmfc.cc * 100 + 1; + fmask |= DTK_M(YEAR); } if (tmfc.j) + { j2date(tmfc.j, &tm->tm_year, &tm->tm_mon, &tm->tm_mday); + fmask |= DTK_DATE_M; + } if (tmfc.ww) { @@ -3734,6 +3739,7 @@ do_to_timestamp(text *date_txt, text *fmt, isoweekdate2date(tmfc.ww, tmfc.d, &tm->tm_year, &tm->tm_mon, &tm->tm_mday); else isoweek2date(tmfc.ww, &tm->tm_year, &tm->tm_mon, &tm->tm_mday); + fmask |= DTK_DATE_M; } else tmfc.ddd = (tmfc.ww - 1) * 7 + 1; @@ -3744,11 +3750,17 @@ do_to_timestamp(text *date_txt, text *fmt, if (tmfc.d) tm->tm_wday = tmfc.d - 1; /* convert to native numbering */ if (tmfc.dd) + { tm->tm_mday = tmfc.dd; + fmask |= DTK_M(DAY); + } if (tmfc.ddd) tm->tm_yday = tmfc.ddd; if (tmfc.mm) + { tm->tm_mon = tmfc.mm; + fmask |= DTK_M(MONTH); + } if (tmfc.ddd && (tm->tm_mon <= 1 || tm->tm_mday <= 1)) { @@ -3771,6 +3783,7 @@ do_to_timestamp(text *date_txt, text *fmt, j0 = isoweek2j(tm->tm_year, 1) - 1; j2date(j0 + tmfc.ddd, &tm->tm_year, &tm->tm_mon, &tm->tm_mday); + fmask |= DTK_DATE_M; } else { @@ -3793,9 +3806,24 @@ do_to_timestamp(text *date_txt, text *fmt, if (tm->tm_mday <= 1) tm->tm_mday = tmfc.ddd - y[i - 1]; + + fmask |= DTK_M(MONTH) | DTK_M(DAY); } } + /* Validate date with bit mask received above */ + if (fmask != 0 && date_str) + { + if (ValidateDate(fmask, false, false, false, tm) != 0) + ereport(ERROR, + (errcode(ERRCODE_DATETIME_FIELD_OVERFLOW), + errmsg("date/time field value out of range: \"%s\"", + date_str))); + } + + if (date_str) + pfree(date_str); + #ifdef HAVE_INT64_TIMESTAMP if (tmfc.ms) *fsec += tmfc.ms * 1000;
-- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers