8
8
*
9
9
*
10
10
* IDENTIFICATION
11
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/datetime.c,v 1.97 2002/11/13 17:24:05 tgl Exp $
11
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/datetime.c,v 1.98 2003/01/16 00:26:45 tgl Exp $
12
12
*
13
13
*-------------------------------------------------------------------------
14
14
*/
15
15
#include "postgres.h"
16
16
17
17
#include <ctype.h>
18
- #include <math.h>
19
18
#include <errno.h>
20
19
#include <float.h>
21
20
#include <limits.h>
21
+ #include <math.h>
22
22
23
23
#include "miscadmin.h"
24
- #include "utils/guc.h"
25
24
#include "utils/datetime.h"
25
+ #include "utils/guc.h"
26
26
27
27
28
28
static int DecodeNumber (int flen ,char * field ,
@@ -37,7 +37,7 @@ static intDecodeTimezone(char *str, int *tzp);
37
37
static datetkn * datebsearch (char * key ,datetkn * base ,unsignedint nel );
38
38
static int DecodeDate (char * str ,int fmask ,int * tmask ,struct tm * tm );
39
39
static int DecodePosixTimezone (char * str ,int * val );
40
- void TrimTrailingZeros (char * str );
40
+ static void TrimTrailingZeros (char * str );
41
41
42
42
43
43
int day_tab [2 ][13 ]= {
@@ -69,14 +69,16 @@ char *days[] = {"Sunday", "Monday", "Tuesday", "Wednesday",
69
69
#define TOVAL (tp ,v )((tp)->value = ((v) < 0? NEG((-(v))/15): POS(v)/15))
70
70
71
71
/*
72
- * datetktbl holds date/time keywords. Note that this table must be strictly
73
- * ordered to allow an O(ln(N)) search algorithm.
72
+ * datetktbl holds date/time keywords.
73
+ *
74
+ * Note that this table must be strictly alphabetically ordered to allow an
75
+ * O(ln(N)) search algorithm to be used.
74
76
*
75
- * The text field isnot guaranteed to be NULL-terminated.
77
+ * The text field isNOT guaranteed to be NULL-terminated.
76
78
*
77
79
* To keep this table reasonably small, we divide the lexval for TZ and DTZ
78
80
* entries by 15 (so they are on 15 minute boundaries) and truncate the text
79
- * field atMAXTOKLEN characters.
81
+ * field atTOKMAXLEN characters.
80
82
* Formerly, we divided by 10 rather than 15 but there are a few time zones
81
83
* which are 30 or 45 minutes away from an even hour, most are on an hour
82
84
* boundary, and none on other boundaries.
@@ -88,11 +90,11 @@ char *days[] = {"Sunday", "Monday", "Tuesday", "Wednesday",
88
90
static datetkn datetktbl []= {
89
91
/*text, token, lexval */
90
92
{EARLY ,RESERV ,DTK_EARLY },/* "-infinity" reserved for "early time" */
93
+ {"abstime" ,IGNORE_DTF ,0 },/* for pre-v6.1 "Invalid Abstime" */
91
94
{"acsst" ,DTZ ,POS (42 )},/* Cent. Australia */
92
95
{"acst" ,DTZ ,NEG (16 )},/* Atlantic/Porto Acre */
93
96
{"act" ,TZ ,NEG (20 )},/* Atlantic/Porto Acre */
94
97
{DA_D ,ADBC ,AD },/* "ad" for years >= 0 */
95
- {"abstime" ,IGNORE_DTF ,0 },/* for pre-v6.1 "Invalid Abstime" */
96
98
{"adt" ,DTZ ,NEG (12 )},/* Atlantic Daylight Time */
97
99
{"aesst" ,DTZ ,POS (44 )},/* E. Australia */
98
100
{"aest" ,TZ ,POS (40 )},/* Australia Eastern Std Time */
@@ -101,16 +103,18 @@ static datetkn datetktbl[] = {
101
103
{"akdt" ,DTZ ,NEG (32 )},/* Alaska Daylight Time */
102
104
{"akst" ,DTZ ,NEG (36 )},/* Alaska Standard Time */
103
105
{"allballs" ,RESERV ,DTK_ZULU },/* 00:00:00 */
104
- {"almt" ,TZ ,POS (24 )},/* Almaty Time */
105
106
{"almst" ,TZ ,POS (28 )},/* Almaty Savings Time */
107
+ {"almt" ,TZ ,POS (24 )},/* Almaty Time */
106
108
{"am" ,AMPM ,AM },
107
109
{"amst" ,DTZ ,POS (20 )},/* Armenia Summer Time (Yerevan) */
108
- {"amt" ,TZ ,POS (16 )},/* Armenia Time (Yerevan) */
109
110
#if 0
110
111
{"amst" ,DTZ ,NEG (12 )},/* Porto Velho */
111
112
#endif
113
+ {"amt" ,TZ ,POS (16 )},/* Armenia Time (Yerevan) */
112
114
{"anast" ,DTZ ,POS (52 )},/* Anadyr Summer Time (Russia) */
113
115
{"anat" ,TZ ,POS (48 )},/* Anadyr Time (Russia) */
116
+ {"apr" ,MONTH ,4 },
117
+ {"april" ,MONTH ,4 },
114
118
#if 0
115
119
aqtst
116
120
aqtt
@@ -122,8 +126,6 @@ static datetkn datetktbl[] = {
122
126
ast /* Atlantic Standard Time, Arabia Standard
123
127
* Time, Acre Standard Time */
124
128
#endif
125
- {"apr" ,MONTH ,4 },
126
- {"april" ,MONTH ,4 },
127
129
{"ast" ,TZ ,NEG (16 )},/* Atlantic Std Time (Canada) */
128
130
{"at" ,IGNORE_DTF ,0 },/* "at" (throwaway) */
129
131
{"aug" ,MONTH ,8 },
@@ -181,12 +183,12 @@ static datetkn datetktbl[] = {
181
183
#endif
182
184
{"cot" ,TZ ,NEG (20 )},/* Columbia Time */
183
185
{"cst" ,TZ ,NEG (24 )},/* Central Standard Time */
186
+ {DCURRENT ,RESERV ,DTK_CURRENT },/* "current" is always now */
184
187
#if 0
185
188
cvst
186
189
#endif
187
190
{"cvt" ,TZ ,POS (28 )},/* Christmas Island Time (Indian Ocean) */
188
191
{"cxt" ,TZ ,POS (28 )},/* Christmas Island Time (Indian Ocean) */
189
- {DCURRENT ,RESERV ,DTK_CURRENT },/* "current" is always now */
190
192
{"d" ,UNITS ,DTK_DAY },/* "day of month" for ISO input */
191
193
{"davt" ,TZ ,POS (28 )},/* Davis Time (Antarctica) */
192
194
{"ddut" ,TZ ,POS (40 )},/* Dumont-d'Urville Time (Antarctica) */
@@ -414,8 +416,8 @@ static datetkn datetktbl[] = {
414
416
syot
415
417
#endif
416
418
{"t" ,ISOTIME ,DTK_TIME },/* Filler for ISO time fields */
417
- {"that" ,TZ ,NEG (40 )},/* Tahiti Time */
418
419
{"tft" ,TZ ,POS (20 )},/* Kerguelen Time */
420
+ {"that" ,TZ ,NEG (40 )},/* Tahiti Time */
419
421
{"thu" ,DOW ,4 },
420
422
{"thur" ,DOW ,4 },
421
423
{"thurs" ,DOW ,4 },
@@ -516,9 +518,9 @@ static datetkn deltatktbl[] = {
516
518
{DDAY ,UNITS ,DTK_DAY },/* "day" relative */
517
519
{"days" ,UNITS ,DTK_DAY },/* "days" relative */
518
520
{"dec" ,UNITS ,DTK_DECADE },/* "decade" relative */
519
- {"decs" ,UNITS ,DTK_DECADE },/* "decades" relative */
520
521
{DDECADE ,UNITS ,DTK_DECADE },/* "decade" relative */
521
522
{"decades" ,UNITS ,DTK_DECADE },/* "decades" relative */
523
+ {"decs" ,UNITS ,DTK_DECADE },/* "decades" relative */
522
524
{"h" ,UNITS ,DTK_HOUR },/* "hour" relative */
523
525
{DHOUR ,UNITS ,DTK_HOUR },/* "hour" relative */
524
526
{"hours" ,UNITS ,DTK_HOUR },/* "hours" relative */
@@ -534,7 +536,6 @@ static datetkn deltatktbl[] = {
534
536
{"mils" ,UNITS ,DTK_MILLENNIUM },/* "millennia" relative */
535
537
{"min" ,UNITS ,DTK_MINUTE },/* "minute" relative */
536
538
{"mins" ,UNITS ,DTK_MINUTE },/* "minutes" relative */
537
- {"mins" ,UNITS ,DTK_MINUTE },/* "minutes" relative */
538
539
{DMINUTE ,UNITS ,DTK_MINUTE },/* "minute" relative */
539
540
{"minutes" ,UNITS ,DTK_MINUTE },/* "minutes" relative */
540
541
{"mon" ,UNITS ,DTK_MONTH },/* "months" relative */
@@ -555,7 +556,6 @@ static datetkn deltatktbl[] = {
555
556
{"seconds" ,UNITS ,DTK_SECOND },
556
557
{"secs" ,UNITS ,DTK_SECOND },
557
558
{DTIMEZONE ,UNITS ,DTK_TZ },/* "timezone" time offset */
558
- {"timezone" ,UNITS ,DTK_TZ },/* "timezone" time offset */
559
559
{"timezone_h" ,UNITS ,DTK_TZ_HOUR },/* timezone hour units */
560
560
{"timezone_m" ,UNITS ,DTK_TZ_MINUTE },/* timezone minutes units */
561
561
{"undefined" ,RESERV ,DTK_INVALID },/* pre-v6.1 invalid time */
@@ -576,9 +576,9 @@ static datetkn deltatktbl[] = {
576
576
577
577
static unsignedint szdeltatktbl = sizeof deltatktbl /sizeof deltatktbl [0 ];
578
578
579
- datetkn * datecache [MAXDATEFIELDS ]= {NULL };
579
+ static datetkn * datecache [MAXDATEFIELDS ]= {NULL };
580
580
581
- datetkn * deltacache [MAXDATEFIELDS ]= {NULL };
581
+ static datetkn * deltacache [MAXDATEFIELDS ]= {NULL };
582
582
583
583
584
584
/*
@@ -653,7 +653,7 @@ j2day(int date)
653
653
/* TrimTrailingZeros()
654
654
* ... resulting from printing numbers with full precision.
655
655
*/
656
- void
656
+ static void
657
657
TrimTrailingZeros (char * str )
658
658
{
659
659
int len = strlen (str );
@@ -3690,3 +3690,40 @@ ClearDateCache(bool newval, bool doit, bool interactive)
3690
3690
3691
3691
return true;
3692
3692
}
3693
+
3694
+ /*
3695
+ * We've been burnt by stupid errors in the ordering of the datetkn tables
3696
+ * once too often. Arrange to check them during postmaster start.
3697
+ */
3698
+ static bool
3699
+ CheckDateTokenTable (const char * tablename ,datetkn * base ,unsignedint nel )
3700
+ {
3701
+ bool ok = true;
3702
+ unsignedint i ;
3703
+
3704
+ for (i = 1 ;i < nel ;i ++ )
3705
+ {
3706
+ if (strncmp (base [i - 1 ].token ,base [i ].token ,TOKMAXLEN ) >=0 )
3707
+ {
3708
+ elog (LOG ,"Ordering error in %s table: \"%.*s\" >= \"%.*s\"" ,
3709
+ tablename ,
3710
+ TOKMAXLEN ,base [i - 1 ].token ,
3711
+ TOKMAXLEN ,base [i ].token );
3712
+ ok = false;
3713
+ }
3714
+ }
3715
+ return ok ;
3716
+ }
3717
+
3718
+ bool
3719
+ CheckDateTokenTables (void )
3720
+ {
3721
+ bool ok = true;
3722
+
3723
+ ok &=CheckDateTokenTable ("datetktbl" ,datetktbl ,szdatetktbl );
3724
+ ok &=CheckDateTokenTable ("deltatktbl" ,deltatktbl ,szdeltatktbl );
3725
+ ok &=CheckDateTokenTable ("australian_datetktbl" ,
3726
+ australian_datetktbl ,
3727
+ australian_szdatetktbl );
3728
+ return ok ;
3729
+ }