8
8
*
9
9
*
10
10
* IDENTIFICATION
11
- * $PostgreSQL: pgsql/src/backend/utils/adt/datetime.c,v 1.184 2008/01/01 19:45:52 momjian Exp $
11
+ * $PostgreSQL: pgsql/src/backend/utils/adt/datetime.c,v 1.184.2.1 2008/02/25 23:21:08 tgl Exp $
12
12
*
13
13
*-------------------------------------------------------------------------
14
14
*/
@@ -40,7 +40,10 @@ static int DecodeTime(char *str, int fmask, int *tmask,
40
40
struct pg_tm * tm , fsec_t * fsec );
41
41
static int DecodeTimezone (char * str , int * tzp );
42
42
static 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 );
44
47
static void TrimTrailingZeros (char * str );
45
48
46
49
@@ -803,7 +806,8 @@ DecodeDateTime(char **field, int *ftype, int nf,
803
806
}
804
807
else
805
808
{
806
- dterr = DecodeDate (field [i ], fmask , & tmask , tm );
809
+ dterr = DecodeDate (field [i ], fmask ,
810
+ & tmask , & is2digits , tm );
807
811
if (dterr )
808
812
return dterr ;
809
813
}
@@ -998,7 +1002,8 @@ DecodeDateTime(char **field, int *ftype, int nf,
998
1002
/* Embedded decimal and no date yet? */
999
1003
if (cp != NULL && !(fmask & DTK_DATE_M ))
1000
1004
{
1001
- dterr = DecodeDate (field [i ], fmask , & tmask , tm );
1005
+ dterr = DecodeDate (field [i ], fmask ,
1006
+ & tmask , & is2digits , tm );
1002
1007
if (dterr )
1003
1008
return dterr ;
1004
1009
}
@@ -1232,51 +1237,14 @@ DecodeDateTime(char **field, int *ftype, int nf,
1232
1237
if (tmask & fmask )
1233
1238
return DTERR_BAD_FORMAT ;
1234
1239
fmask |= tmask ;
1235
- }
1236
-
1237
- if (fmask & DTK_M (YEAR ))
1238
- {
1239
- /* there is no year zero in AD/BC notation; i.e. "1 BC" == year 0 */
1240
- if (bc )
1241
- {
1242
- if (tm -> tm_year > 0 )
1243
- tm -> tm_year = - (tm -> tm_year - 1 );
1244
- else
1245
- ereport (ERROR ,
1246
- (errcode (ERRCODE_INVALID_DATETIME_FORMAT ),
1247
- errmsg ("inconsistent use of year %04d and \"BC\"" ,
1248
- tm -> tm_year )));
1249
- }
1250
- else if (is2digits )
1251
- {
1252
- if (tm -> tm_year < 70 )
1253
- tm -> tm_year += 2000 ;
1254
- else if (tm -> tm_year < 100 )
1255
- tm -> tm_year += 1900 ;
1256
- }
1257
- }
1258
-
1259
- /* now that we have correct year, decode DOY */
1260
- if (fmask & DTK_M (DOY ))
1261
- {
1262
- j2date (date2j (tm -> tm_year , 1 , 1 ) + tm -> tm_yday - 1 ,
1263
- & tm -> tm_year , & tm -> tm_mon , & tm -> tm_mday );
1264
- }
1265
-
1266
- /* check for valid month */
1267
- if (fmask & DTK_M (MONTH ))
1268
- {
1269
- if (tm -> tm_mon < 1 || tm -> tm_mon > MONTHS_PER_YEAR )
1270
- return DTERR_MD_FIELD_OVERFLOW ;
1271
- }
1240
+ } /* end loop over fields */
1272
1241
1273
- /* minimal check for valid day */
1274
- if (fmask & DTK_M (DAY ))
1275
- {
1276
- if (tm -> tm_mday < 1 || tm -> tm_mday > 31 )
1277
- return DTERR_MD_FIELD_OVERFLOW ;
1278
- }
1242
+ /* do final checking/adjustment of Y/M/D fields */
1243
+ dterr = ValidateDate (fmask , is2digits , bc , tm );
1244
+ if (dterr )
1245
+ return dterr ;
1279
1246
1247
+ /* handle AM/PM */
1280
1248
if (mer != HR24 && tm -> tm_hour > 12 )
1281
1249
return DTERR_FIELD_OVERFLOW ;
1282
1250
if (mer == AM && tm -> tm_hour == 12 )
@@ -1294,14 +1262,6 @@ DecodeDateTime(char **field, int *ftype, int nf,
1294
1262
return DTERR_BAD_FORMAT ;
1295
1263
}
1296
1264
1297
- /*
1298
- * Check for valid day of month, now that we know for sure the month
1299
- * and year. Note we don't use MD_FIELD_OVERFLOW here, since it seems
1300
- * unlikely that "Feb 29" is a YMD-order error.
1301
- */
1302
- if (tm -> tm_mday > day_tab [isleap (tm -> tm_year )][tm -> tm_mon - 1 ])
1303
- return DTERR_FIELD_OVERFLOW ;
1304
-
1305
1265
/*
1306
1266
* If we had a full timezone spec, compute the offset (we could not do
1307
1267
* it before, because we need the date to resolve DST status).
@@ -1484,6 +1444,7 @@ DecodeTimeOnly(char **field, int *ftype, int nf,
1484
1444
int val ;
1485
1445
int dterr ;
1486
1446
bool is2digits = FALSE;
1447
+ bool bc = FALSE;
1487
1448
int mer = HR24 ;
1488
1449
pg_tz * namedTz = NULL ;
1489
1450
@@ -1515,7 +1476,8 @@ DecodeTimeOnly(char **field, int *ftype, int nf,
1515
1476
if (i == 0 && nf >= 2 &&
1516
1477
(ftype [nf - 1 ] == DTK_DATE || ftype [1 ] == DTK_TIME ))
1517
1478
{
1518
- dterr = DecodeDate (field [i ], fmask , & tmask , tm );
1479
+ dterr = DecodeDate (field [i ], fmask ,
1480
+ & tmask , & is2digits , tm );
1519
1481
if (dterr )
1520
1482
return dterr ;
1521
1483
}
@@ -1781,7 +1743,8 @@ DecodeTimeOnly(char **field, int *ftype, int nf,
1781
1743
*/
1782
1744
if (i == 0 && nf >= 2 && ftype [nf - 1 ] == DTK_DATE )
1783
1745
{
1784
- dterr = DecodeDate (field [i ], fmask , & tmask , tm );
1746
+ dterr = DecodeDate (field [i ], fmask ,
1747
+ & tmask , & is2digits , tm );
1785
1748
if (dterr )
1786
1749
return dterr ;
1787
1750
}
@@ -1910,6 +1873,10 @@ DecodeTimeOnly(char **field, int *ftype, int nf,
1910
1873
mer = val ;
1911
1874
break ;
1912
1875
1876
+ case ADBC :
1877
+ bc = (val == BC );
1878
+ break ;
1879
+
1913
1880
case UNITS :
1914
1881
tmask = 0 ;
1915
1882
ptype = val ;
@@ -1958,8 +1925,14 @@ DecodeTimeOnly(char **field, int *ftype, int nf,
1958
1925
if (tmask & fmask )
1959
1926
return DTERR_BAD_FORMAT ;
1960
1927
fmask |= tmask ;
1961
- }
1928
+ } /* end loop over fields */
1962
1929
1930
+ /* do final checking/adjustment of Y/M/D fields */
1931
+ dterr = ValidateDate (fmask , is2digits , bc , tm );
1932
+ if (dterr )
1933
+ return dterr ;
1934
+
1935
+ /* handle AM/PM */
1963
1936
if (mer != HR24 && tm -> tm_hour > 12 )
1964
1937
return DTERR_FIELD_OVERFLOW ;
1965
1938
if (mer == AM && tm -> tm_hour == 12 )
@@ -2045,24 +2018,29 @@ DecodeTimeOnly(char **field, int *ftype, int nf,
2045
2018
* Decode date string which includes delimiters.
2046
2019
* Return 0 if okay, a DTERR code if not.
2047
2020
*
2048
- * Insist on a complete set of fields.
2021
+ * str: field to be parsed
2022
+ * fmask: bitmask for field types already seen
2023
+ * *tmask: receives bitmask for fields found here
2024
+ * *is2digits: set to TRUE if we find 2-digit year
2025
+ * *tm: field values are stored into appropriate members of this struct
2049
2026
*/
2050
2027
static int
2051
- DecodeDate (char * str , int fmask , int * tmask , struct pg_tm * tm )
2028
+ DecodeDate (char * str , int fmask , int * tmask , bool * is2digits ,
2029
+ struct pg_tm * tm )
2052
2030
{
2053
2031
fsec_t fsec ;
2054
2032
int nf = 0 ;
2055
2033
int i ,
2056
2034
len ;
2057
2035
int dterr ;
2058
2036
bool haveTextMonth = FALSE;
2059
- bool bc = FALSE;
2060
- bool is2digits = FALSE;
2061
2037
int type ,
2062
2038
val ,
2063
2039
dmask = 0 ;
2064
2040
char * field [MAXDATEFIELDS ];
2065
2041
2042
+ * tmask = 0 ;
2043
+
2066
2044
/* parse this string... */
2067
2045
while (* str != '\0' && nf < MAXDATEFIELDS )
2068
2046
{
@@ -2088,14 +2066,6 @@ DecodeDate(char *str, int fmask, int *tmask, struct pg_tm * tm)
2088
2066
nf ++ ;
2089
2067
}
2090
2068
2091
- #if 0
2092
- /* don't allow too many fields */
2093
- if (nf > 3 )
2094
- return DTERR_BAD_FORMAT ;
2095
- #endif
2096
-
2097
- * tmask = 0 ;
2098
-
2099
2069
/* look first for text fields, since that will be unambiguous month */
2100
2070
for (i = 0 ; i < nf ; i ++ )
2101
2071
{
@@ -2113,10 +2083,6 @@ DecodeDate(char *str, int fmask, int *tmask, struct pg_tm * tm)
2113
2083
haveTextMonth = TRUE;
2114
2084
break ;
2115
2085
2116
- case ADBC :
2117
- bc = (val == BC );
2118
- break ;
2119
-
2120
2086
default :
2121
2087
return DTERR_BAD_FORMAT ;
2122
2088
}
@@ -2142,7 +2108,7 @@ DecodeDate(char *str, int fmask, int *tmask, struct pg_tm * tm)
2142
2108
2143
2109
dterr = DecodeNumber (len , field [i ], haveTextMonth , fmask ,
2144
2110
& dmask , tm ,
2145
- & fsec , & is2digits );
2111
+ & fsec , is2digits );
2146
2112
if (dterr )
2147
2113
return dterr ;
2148
2114
@@ -2156,23 +2122,38 @@ DecodeDate(char *str, int fmask, int *tmask, struct pg_tm * tm)
2156
2122
if ((fmask & ~(DTK_M (DOY ) | DTK_M (TZ ))) != DTK_DATE_M )
2157
2123
return DTERR_BAD_FORMAT ;
2158
2124
2159
- /* there is no year zero in AD/BC notation; i.e. "1 BC" == year 0 */
2160
- if (bc )
2161
- {
2162
- if (tm -> tm_year > 0 )
2163
- tm -> tm_year = - (tm -> tm_year - 1 );
2164
- else
2165
- ereport (ERROR ,
2166
- (errcode (ERRCODE_INVALID_DATETIME_FORMAT ),
2167
- errmsg ("inconsistent use of year %04d and \"BC\"" ,
2168
- tm -> tm_year )));
2169
- }
2170
- else if (is2digits )
2125
+ /* validation of the field values must wait until ValidateDate() */
2126
+
2127
+ return 0 ;
2128
+ }
2129
+
2130
+ /* ValidateDate()
2131
+ * Check valid year/month/day values, handle BC and DOY cases
2132
+ * Return 0 if okay, a DTERR code if not.
2133
+ */
2134
+ static int
2135
+ ValidateDate (int fmask , bool is2digits , bool bc , struct pg_tm * tm )
2136
+ {
2137
+ if (fmask & DTK_M (YEAR ))
2171
2138
{
2172
- if (tm -> tm_year < 70 )
2173
- tm -> tm_year += 2000 ;
2174
- else if (tm -> tm_year < 100 )
2175
- tm -> tm_year += 1900 ;
2139
+ /* there is no year zero in AD/BC notation; i.e. "1 BC" == year 0 */
2140
+ if (bc )
2141
+ {
2142
+ if (tm -> tm_year > 0 )
2143
+ tm -> tm_year = - (tm -> tm_year - 1 );
2144
+ else
2145
+ ereport (ERROR ,
2146
+ (errcode (ERRCODE_INVALID_DATETIME_FORMAT ),
2147
+ errmsg ("inconsistent use of year %04d and \"BC\"" ,
2148
+ tm -> tm_year )));
2149
+ }
2150
+ else if (is2digits )
2151
+ {
2152
+ if (tm -> tm_year < 70 )
2153
+ tm -> tm_year += 2000 ;
2154
+ else if (tm -> tm_year < 100 )
2155
+ tm -> tm_year += 1900 ;
2156
+ }
2176
2157
}
2177
2158
2178
2159
/* now that we have correct year, decode DOY */
@@ -2183,16 +2164,29 @@ DecodeDate(char *str, int fmask, int *tmask, struct pg_tm * tm)
2183
2164
}
2184
2165
2185
2166
/* check for valid month */
2186
- if (tm -> tm_mon < 1 || tm -> tm_mon > MONTHS_PER_YEAR )
2187
- return DTERR_MD_FIELD_OVERFLOW ;
2167
+ if (fmask & DTK_M (MONTH ))
2168
+ {
2169
+ if (tm -> tm_mon < 1 || tm -> tm_mon > MONTHS_PER_YEAR )
2170
+ return DTERR_MD_FIELD_OVERFLOW ;
2171
+ }
2188
2172
2189
- /* check for valid day */
2190
- if (tm -> tm_mday < 1 || tm -> tm_mday > 31 )
2191
- return DTERR_MD_FIELD_OVERFLOW ;
2173
+ /* minimal check for valid day */
2174
+ if (fmask & DTK_M (DAY ))
2175
+ {
2176
+ if (tm -> tm_mday < 1 || tm -> tm_mday > 31 )
2177
+ return DTERR_MD_FIELD_OVERFLOW ;
2178
+ }
2192
2179
2193
- /* We don't want to hint about DateStyle for Feb 29 */
2194
- if (tm -> tm_mday > day_tab [isleap (tm -> tm_year )][tm -> tm_mon - 1 ])
2195
- return DTERR_FIELD_OVERFLOW ;
2180
+ if ((fmask & DTK_DATE_M ) == DTK_DATE_M )
2181
+ {
2182
+ /*
2183
+ * Check for valid day of month, now that we know for sure the month
2184
+ * and year. Note we don't use MD_FIELD_OVERFLOW here, since it seems
2185
+ * unlikely that "Feb 29" is a YMD-order error.
2186
+ */
2187
+ if (tm -> tm_mday > day_tab [isleap (tm -> tm_year )][tm -> tm_mon - 1 ])
2188
+ return DTERR_FIELD_OVERFLOW ;
2189
+ }
2196
2190
2197
2191
return 0 ;
2198
2192
}
0 commit comments