88 *
99 *
1010 * IDENTIFICATION
11- * $PostgreSQL: pgsql/src/backend/utils/adt/datetime.c,v 1.185 2008/02/17 02:09:28 tgl Exp $
11+ * $PostgreSQL: pgsql/src/backend/utils/adt/datetime.c,v 1.186 2008/02/25 23:21:01 tgl Exp $
1212 *
1313 *-------------------------------------------------------------------------
1414 */
@@ -40,7 +40,10 @@ static int DecodeTime(char *str, int fmask, int *tmask,
4040 struct pg_tm * tm , fsec_t * fsec );
4141static int DecodeTimezone (char * str , int * tzp );
4242static const datetkn * datebsearch (const char * key , const datetkn * base , int nel );
43- static int DecodeDate (char * str , int fmask , int * tmask , struct pg_tm * tm );
43+ static int DecodeDate (char * str , int fmask , int * tmask , bool * is2digits ,
44+ struct pg_tm * tm );
45+ static int ValidateDate (int fmask , bool is2digits , bool bc ,
46+ struct pg_tm * tm );
4447static void TrimTrailingZeros (char * str );
4548
4649
@@ -805,7 +808,8 @@ DecodeDateTime(char **field, int *ftype, int nf,
805808 }
806809 else
807810 {
808- dterr = DecodeDate (field [i ], fmask , & tmask , tm );
811+ dterr = DecodeDate (field [i ], fmask ,
812+ & tmask , & is2digits , tm );
809813 if (dterr )
810814 return dterr ;
811815 }
@@ -1000,7 +1004,8 @@ DecodeDateTime(char **field, int *ftype, int nf,
10001004 /* Embedded decimal and no date yet? */
10011005 if (cp != NULL && !(fmask & DTK_DATE_M ))
10021006 {
1003- dterr = DecodeDate (field [i ], fmask , & tmask , tm );
1007+ dterr = DecodeDate (field [i ], fmask ,
1008+ & tmask , & is2digits , tm );
10041009 if (dterr )
10051010 return dterr ;
10061011 }
@@ -1234,51 +1239,14 @@ DecodeDateTime(char **field, int *ftype, int nf,
12341239 if (tmask & fmask )
12351240 return DTERR_BAD_FORMAT ;
12361241 fmask |= tmask ;
1237- }
1238-
1239- if (fmask & DTK_M (YEAR ))
1240- {
1241- /* there is no year zero in AD/BC notation; i.e. "1 BC" == year 0 */
1242- if (bc )
1243- {
1244- if (tm -> tm_year > 0 )
1245- tm -> tm_year = - (tm -> tm_year - 1 );
1246- else
1247- ereport (ERROR ,
1248- (errcode (ERRCODE_INVALID_DATETIME_FORMAT ),
1249- errmsg ("inconsistent use of year %04d and \"BC\"" ,
1250- tm -> tm_year )));
1251- }
1252- else if (is2digits )
1253- {
1254- if (tm -> tm_year < 70 )
1255- tm -> tm_year += 2000 ;
1256- else if (tm -> tm_year < 100 )
1257- tm -> tm_year += 1900 ;
1258- }
1259- }
1260-
1261- /* now that we have correct year, decode DOY */
1262- if (fmask & DTK_M (DOY ))
1263- {
1264- j2date (date2j (tm -> tm_year , 1 , 1 ) + tm -> tm_yday - 1 ,
1265- & tm -> tm_year , & tm -> tm_mon , & tm -> tm_mday );
1266- }
1267-
1268- /* check for valid month */
1269- if (fmask & DTK_M (MONTH ))
1270- {
1271- if (tm -> tm_mon < 1 || tm -> tm_mon > MONTHS_PER_YEAR )
1272- return DTERR_MD_FIELD_OVERFLOW ;
1273- }
1242+ } /* end loop over fields */
12741243
1275- /* minimal check for valid day */
1276- if (fmask & DTK_M (DAY ))
1277- {
1278- if (tm -> tm_mday < 1 || tm -> tm_mday > 31 )
1279- return DTERR_MD_FIELD_OVERFLOW ;
1280- }
1244+ /* do final checking/adjustment of Y/M/D fields */
1245+ dterr = ValidateDate (fmask , is2digits , bc , tm );
1246+ if (dterr )
1247+ return dterr ;
12811248
1249+ /* handle AM/PM */
12821250 if (mer != HR24 && tm -> tm_hour > 12 )
12831251 return DTERR_FIELD_OVERFLOW ;
12841252 if (mer == AM && tm -> tm_hour == 12 )
@@ -1296,14 +1264,6 @@ DecodeDateTime(char **field, int *ftype, int nf,
12961264 return DTERR_BAD_FORMAT ;
12971265 }
12981266
1299- /*
1300- * Check for valid day of month, now that we know for sure the month
1301- * and year. Note we don't use MD_FIELD_OVERFLOW here, since it seems
1302- * unlikely that "Feb 29" is a YMD-order error.
1303- */
1304- if (tm -> tm_mday > day_tab [isleap (tm -> tm_year )][tm -> tm_mon - 1 ])
1305- return DTERR_FIELD_OVERFLOW ;
1306-
13071267 /*
13081268 * If we had a full timezone spec, compute the offset (we could not do
13091269 * it before, because we need the date to resolve DST status).
@@ -1486,6 +1446,7 @@ DecodeTimeOnly(char **field, int *ftype, int nf,
14861446 int val ;
14871447 int dterr ;
14881448 bool is2digits = FALSE;
1449+ bool bc = FALSE;
14891450 int mer = HR24 ;
14901451 pg_tz * namedTz = NULL ;
14911452
@@ -1517,7 +1478,8 @@ DecodeTimeOnly(char **field, int *ftype, int nf,
15171478 if (i == 0 && nf >= 2 &&
15181479 (ftype [nf - 1 ] == DTK_DATE || ftype [1 ] == DTK_TIME ))
15191480 {
1520- dterr = DecodeDate (field [i ], fmask , & tmask , tm );
1481+ dterr = DecodeDate (field [i ], fmask ,
1482+ & tmask , & is2digits , tm );
15211483 if (dterr )
15221484 return dterr ;
15231485 }
@@ -1783,7 +1745,8 @@ DecodeTimeOnly(char **field, int *ftype, int nf,
17831745 */
17841746 if (i == 0 && nf >= 2 && ftype [nf - 1 ] == DTK_DATE )
17851747 {
1786- dterr = DecodeDate (field [i ], fmask , & tmask , tm );
1748+ dterr = DecodeDate (field [i ], fmask ,
1749+ & tmask , & is2digits , tm );
17871750 if (dterr )
17881751 return dterr ;
17891752 }
@@ -1912,6 +1875,10 @@ DecodeTimeOnly(char **field, int *ftype, int nf,
19121875 mer = val ;
19131876 break ;
19141877
1878+ case ADBC :
1879+ bc = (val == BC );
1880+ break ;
1881+
19151882 case UNITS :
19161883 tmask = 0 ;
19171884 ptype = val ;
@@ -1960,8 +1927,14 @@ DecodeTimeOnly(char **field, int *ftype, int nf,
19601927 if (tmask & fmask )
19611928 return DTERR_BAD_FORMAT ;
19621929 fmask |= tmask ;
1963- }
1930+ } /* end loop over fields */
19641931
1932+ /* do final checking/adjustment of Y/M/D fields */
1933+ dterr = ValidateDate (fmask , is2digits , bc , tm );
1934+ if (dterr )
1935+ return dterr ;
1936+
1937+ /* handle AM/PM */
19651938 if (mer != HR24 && tm -> tm_hour > 12 )
19661939 return DTERR_FIELD_OVERFLOW ;
19671940 if (mer == AM && tm -> tm_hour == 12 )
@@ -2047,24 +2020,29 @@ DecodeTimeOnly(char **field, int *ftype, int nf,
20472020 * Decode date string which includes delimiters.
20482021 * Return 0 if okay, a DTERR code if not.
20492022 *
2050- * Insist on a complete set of fields.
2023+ * str: field to be parsed
2024+ * fmask: bitmask for field types already seen
2025+ * *tmask: receives bitmask for fields found here
2026+ * *is2digits: set to TRUE if we find 2-digit year
2027+ * *tm: field values are stored into appropriate members of this struct
20512028 */
20522029static int
2053- DecodeDate (char * str , int fmask , int * tmask , struct pg_tm * tm )
2030+ DecodeDate (char * str , int fmask , int * tmask , bool * is2digits ,
2031+ struct pg_tm * tm )
20542032{
20552033 fsec_t fsec ;
20562034 int nf = 0 ;
20572035 int i ,
20582036 len ;
20592037 int dterr ;
20602038 bool haveTextMonth = FALSE;
2061- bool bc = FALSE;
2062- bool is2digits = FALSE;
20632039 int type ,
20642040 val ,
20652041 dmask = 0 ;
20662042 char * field [MAXDATEFIELDS ];
20672043
2044+ * tmask = 0 ;
2045+
20682046 /* parse this string... */
20692047 while (* str != '\0' && nf < MAXDATEFIELDS )
20702048 {
@@ -2090,14 +2068,6 @@ DecodeDate(char *str, int fmask, int *tmask, struct pg_tm * tm)
20902068 nf ++ ;
20912069 }
20922070
2093- #if 0
2094- /* don't allow too many fields */
2095- if (nf > 3 )
2096- return DTERR_BAD_FORMAT ;
2097- #endif
2098-
2099- * tmask = 0 ;
2100-
21012071 /* look first for text fields, since that will be unambiguous month */
21022072 for (i = 0 ; i < nf ; i ++ )
21032073 {
@@ -2115,10 +2085,6 @@ DecodeDate(char *str, int fmask, int *tmask, struct pg_tm * tm)
21152085 haveTextMonth = TRUE;
21162086 break ;
21172087
2118- case ADBC :
2119- bc = (val == BC );
2120- break ;
2121-
21222088 default :
21232089 return DTERR_BAD_FORMAT ;
21242090 }
@@ -2144,7 +2110,7 @@ DecodeDate(char *str, int fmask, int *tmask, struct pg_tm * tm)
21442110
21452111 dterr = DecodeNumber (len , field [i ], haveTextMonth , fmask ,
21462112 & dmask , tm ,
2147- & fsec , & is2digits );
2113+ & fsec , is2digits );
21482114 if (dterr )
21492115 return dterr ;
21502116
@@ -2158,23 +2124,38 @@ DecodeDate(char *str, int fmask, int *tmask, struct pg_tm * tm)
21582124 if ((fmask & ~(DTK_M (DOY ) | DTK_M (TZ ))) != DTK_DATE_M )
21592125 return DTERR_BAD_FORMAT ;
21602126
2161- /* there is no year zero in AD/BC notation; i.e. "1 BC" == year 0 */
2162- if (bc )
2163- {
2164- if (tm -> tm_year > 0 )
2165- tm -> tm_year = - (tm -> tm_year - 1 );
2166- else
2167- ereport (ERROR ,
2168- (errcode (ERRCODE_INVALID_DATETIME_FORMAT ),
2169- errmsg ("inconsistent use of year %04d and \"BC\"" ,
2170- tm -> tm_year )));
2171- }
2172- else if (is2digits )
2127+ /* validation of the field values must wait until ValidateDate() */
2128+
2129+ return 0 ;
2130+ }
2131+
2132+ /* ValidateDate()
2133+ * Check valid year/month/day values, handle BC and DOY cases
2134+ * Return 0 if okay, a DTERR code if not.
2135+ */
2136+ static int
2137+ ValidateDate (int fmask , bool is2digits , bool bc , struct pg_tm * tm )
2138+ {
2139+ if (fmask & DTK_M (YEAR ))
21732140 {
2174- if (tm -> tm_year < 70 )
2175- tm -> tm_year += 2000 ;
2176- else if (tm -> tm_year < 100 )
2177- tm -> tm_year += 1900 ;
2141+ /* there is no year zero in AD/BC notation; i.e. "1 BC" == year 0 */
2142+ if (bc )
2143+ {
2144+ if (tm -> tm_year > 0 )
2145+ tm -> tm_year = - (tm -> tm_year - 1 );
2146+ else
2147+ ereport (ERROR ,
2148+ (errcode (ERRCODE_INVALID_DATETIME_FORMAT ),
2149+ errmsg ("inconsistent use of year %04d and \"BC\"" ,
2150+ tm -> tm_year )));
2151+ }
2152+ else if (is2digits )
2153+ {
2154+ if (tm -> tm_year < 70 )
2155+ tm -> tm_year += 2000 ;
2156+ else if (tm -> tm_year < 100 )
2157+ tm -> tm_year += 1900 ;
2158+ }
21782159 }
21792160
21802161 /* now that we have correct year, decode DOY */
@@ -2185,16 +2166,29 @@ DecodeDate(char *str, int fmask, int *tmask, struct pg_tm * tm)
21852166 }
21862167
21872168 /* check for valid month */
2188- if (tm -> tm_mon < 1 || tm -> tm_mon > MONTHS_PER_YEAR )
2189- return DTERR_MD_FIELD_OVERFLOW ;
2169+ if (fmask & DTK_M (MONTH ))
2170+ {
2171+ if (tm -> tm_mon < 1 || tm -> tm_mon > MONTHS_PER_YEAR )
2172+ return DTERR_MD_FIELD_OVERFLOW ;
2173+ }
21902174
2191- /* check for valid day */
2192- if (tm -> tm_mday < 1 || tm -> tm_mday > 31 )
2193- return DTERR_MD_FIELD_OVERFLOW ;
2175+ /* minimal check for valid day */
2176+ if (fmask & DTK_M (DAY ))
2177+ {
2178+ if (tm -> tm_mday < 1 || tm -> tm_mday > 31 )
2179+ return DTERR_MD_FIELD_OVERFLOW ;
2180+ }
21942181
2195- /* We don't want to hint about DateStyle for Feb 29 */
2196- if (tm -> tm_mday > day_tab [isleap (tm -> tm_year )][tm -> tm_mon - 1 ])
2197- return DTERR_FIELD_OVERFLOW ;
2182+ if ((fmask & DTK_DATE_M ) == DTK_DATE_M )
2183+ {
2184+ /*
2185+ * Check for valid day of month, now that we know for sure the month
2186+ * and year. Note we don't use MD_FIELD_OVERFLOW here, since it seems
2187+ * unlikely that "Feb 29" is a YMD-order error.
2188+ */
2189+ if (tm -> tm_mday > day_tab [isleap (tm -> tm_year )][tm -> tm_mon - 1 ])
2190+ return DTERR_FIELD_OVERFLOW ;
2191+ }
21982192
21992193 return 0 ;
22002194}
0 commit comments