~vcs-imports/mammoth-replicator/trunk

« back to all changes in this revision

Viewing changes to src/backend/utils/adt/datetime.c

  • Committer: alvherre
  • Date: 2005-12-16 21:24:52 UTC
  • Revision ID: svn-v4:db760fc0-0f08-0410-9d63-cc6633f64896:trunk:1
Initial import of the REL8_0_3 sources from the Pgsql CVS repository.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*-------------------------------------------------------------------------
 
2
 *
 
3
 * datetime.c
 
4
 *        Support functions for date/time types.
 
5
 *
 
6
 * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
 
7
 * Portions Copyright (c) 1994, Regents of the University of California
 
8
 *
 
9
 *
 
10
 * IDENTIFICATION
 
11
 *        $PostgreSQL: pgsql/src/backend/utils/adt/datetime.c,v 1.137.4.1 2005-04-20 17:14:58 tgl Exp $
 
12
 *
 
13
 *-------------------------------------------------------------------------
 
14
 */
 
15
#include "postgres.h"
 
16
 
 
17
#include <ctype.h>
 
18
#include <errno.h>
 
19
#include <float.h>
 
20
#include <limits.h>
 
21
#include <math.h>
 
22
 
 
23
#include "miscadmin.h"
 
24
#include "utils/datetime.h"
 
25
#include "utils/guc.h"
 
26
 
 
27
 
 
28
static int DecodeNumber(int flen, char *field, bool haveTextMonth,
 
29
                         int fmask, int *tmask,
 
30
                         struct pg_tm * tm, fsec_t *fsec, int *is2digits);
 
31
static int DecodeNumberField(int len, char *str,
 
32
                                  int fmask, int *tmask,
 
33
                                  struct pg_tm * tm, fsec_t *fsec, int *is2digits);
 
34
static int DecodeTime(char *str, int fmask, int *tmask,
 
35
                   struct pg_tm * tm, fsec_t *fsec);
 
36
static int      DecodeTimezone(char *str, int *tzp);
 
37
static int      DecodePosixTimezone(char *str, int *tzp);
 
38
static datetkn *datebsearch(char *key, datetkn *base, unsigned int nel);
 
39
static int      DecodeDate(char *str, int fmask, int *tmask, struct pg_tm * tm);
 
40
static void TrimTrailingZeros(char *str);
 
41
 
 
42
 
 
43
const int       day_tab[2][13] =
 
44
{
 
45
        {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 0},
 
46
        {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 0}
 
47
};
 
48
 
 
49
char       *months[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
 
50
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec", NULL};
 
51
 
 
52
char       *days[] = {"Sunday", "Monday", "Tuesday", "Wednesday",
 
53
"Thursday", "Friday", "Saturday", NULL};
 
54
 
 
55
 
 
56
/*****************************************************************************
 
57
 *       PRIVATE ROUTINES                                                                                                                *
 
58
 *****************************************************************************/
 
59
 
 
60
/*
 
61
 * Definitions for squeezing values into "value"
 
62
 * We set aside a high bit for a sign, and scale the timezone offsets
 
63
 * in minutes by a factor of 15 (so can represent quarter-hour increments).
 
64
 */
 
65
#define ABS_SIGNBIT             ((char) 0200)
 
66
#define VALMASK                 ((char) 0177)
 
67
#define POS(n)                  (n)
 
68
#define NEG(n)                  ((n)|ABS_SIGNBIT)
 
69
#define SIGNEDCHAR(c)   ((c)&ABS_SIGNBIT? -((c)&VALMASK): (c))
 
70
#define FROMVAL(tp)             (-SIGNEDCHAR((tp)->value) * 15) /* uncompress */
 
71
#define TOVAL(tp, v)    ((tp)->value = ((v) < 0? NEG((-(v))/15): POS(v)/15))
 
72
 
 
73
/*
 
74
 * datetktbl holds date/time keywords.
 
75
 *
 
76
 * Note that this table must be strictly alphabetically ordered to allow an
 
77
 * O(ln(N)) search algorithm to be used.
 
78
 *
 
79
 * The text field is NOT guaranteed to be NULL-terminated.
 
80
 *
 
81
 * To keep this table reasonably small, we divide the lexval for TZ and DTZ
 
82
 * entries by 15 (so they are on 15 minute boundaries) and truncate the text
 
83
 * field at TOKMAXLEN characters.
 
84
 * Formerly, we divided by 10 rather than 15 but there are a few time zones
 
85
 * which are 30 or 45 minutes away from an even hour, most are on an hour
 
86
 * boundary, and none on other boundaries.
 
87
 *
 
88
 * Let's include all strings from my current zic time zone database.
 
89
 * Not all of them are unique, or even very understandable, so we will
 
90
 * leave some commented out for now.
 
91
 */
 
92
static datetkn datetktbl[] = {
 
93
/*      text, token, lexval */
 
94
        {EARLY, RESERV, DTK_EARLY}, /* "-infinity" reserved for "early time" */
 
95
        {"abstime", IGNORE_DTF, 0}, /* for pre-v6.1 "Invalid Abstime" */
 
96
        {"acsst", DTZ, POS(42)},        /* Cent. Australia */
 
97
        {"acst", DTZ, NEG(16)},         /* Atlantic/Porto Acre Summer Time */
 
98
        {"act", TZ, NEG(20)},           /* Atlantic/Porto Acre Time */
 
99
        {DA_D, ADBC, AD},                       /* "ad" for years > 0 */
 
100
        {"adt", DTZ, NEG(12)},          /* Atlantic Daylight Time */
 
101
        {"aesst", DTZ, POS(44)},        /* E. Australia */
 
102
        {"aest", TZ, POS(40)},          /* Australia Eastern Std Time */
 
103
        {"aft", TZ, POS(18)},           /* Kabul */
 
104
        {"ahst", TZ, NEG(40)},          /* Alaska-Hawaii Std Time */
 
105
        {"akdt", DTZ, NEG(32)},         /* Alaska Daylight Time */
 
106
        {"akst", DTZ, NEG(36)},         /* Alaska Standard Time */
 
107
        {"allballs", RESERV, DTK_ZULU},         /* 00:00:00 */
 
108
        {"almst", TZ, POS(28)},         /* Almaty Savings Time */
 
109
        {"almt", TZ, POS(24)},          /* Almaty Time */
 
110
        {"am", AMPM, AM},
 
111
        {"amst", DTZ, POS(20)},         /* Armenia Summer Time (Yerevan) */
 
112
#if 0
 
113
        {"amst", DTZ, NEG(12)},         /* Amazon Summer Time (Porto Velho) */
 
114
#endif
 
115
        {"amt", TZ, POS(16)},           /* Armenia Time (Yerevan) */
 
116
#if 0
 
117
        {"amt", TZ, NEG(16)},           /* Amazon Time (Porto Velho) */
 
118
#endif
 
119
        {"anast", DTZ, POS(52)},        /* Anadyr Summer Time (Russia) */
 
120
        {"anat", TZ, POS(48)},          /* Anadyr Time (Russia) */
 
121
        {"apr", MONTH, 4},
 
122
        {"april", MONTH, 4},
 
123
#if 0
 
124
        aqtst
 
125
        aqtt
 
126
        arst
 
127
#endif
 
128
        {"art", TZ, NEG(12)},           /* Argentina Time */
 
129
#if 0
 
130
        ashst
 
131
        ast                                                     /* Atlantic Standard Time, Arabia Standard
 
132
                                                                 * Time, Acre Standard Time */
 
133
#endif
 
134
        {"ast", TZ, NEG(16)},           /* Atlantic Std Time (Canada) */
 
135
        {"at", IGNORE_DTF, 0},          /* "at" (throwaway) */
 
136
        {"aug", MONTH, 8},
 
137
        {"august", MONTH, 8},
 
138
        {"awsst", DTZ, POS(36)},        /* W. Australia */
 
139
        {"awst", TZ, POS(32)},          /* W. Australia */
 
140
        {"awt", DTZ, NEG(12)},
 
141
        {"azost", DTZ, POS(0)},         /* Azores Summer Time */
 
142
        {"azot", TZ, NEG(4)},           /* Azores Time */
 
143
        {"azst", DTZ, POS(20)},         /* Azerbaijan Summer Time */
 
144
        {"azt", TZ, POS(16)},           /* Azerbaijan Time */
 
145
        {DB_C, ADBC, BC},                       /* "bc" for years <= 0 */
 
146
        {"bdst", TZ, POS(8)},           /* British Double Summer Time */
 
147
        {"bdt", TZ, POS(24)},           /* Dacca */
 
148
        {"bnt", TZ, POS(32)},           /* Brunei Darussalam Time */
 
149
        {"bort", TZ, POS(32)},          /* Borneo Time (Indonesia) */
 
150
#if 0
 
151
        bortst
 
152
        bost
 
153
#endif
 
154
        {"bot", TZ, NEG(16)},           /* Bolivia Time */
 
155
        {"bra", TZ, NEG(12)},           /* Brazil Time */
 
156
        {"brst", DTZ, NEG(8)},          /* Brasilia Summer Time */
 
157
        {"brt", TZ, NEG(12)},           /* Brasilia Time */
 
158
        {"bst", DTZ, POS(4)},           /* British Summer Time */
 
159
#if 0
 
160
        {"bst", TZ, NEG(12)},           /* Brazil Standard Time */
 
161
        {"bst", DTZ, NEG(44)},          /* Bering Summer Time */
 
162
#endif
 
163
        {"bt", TZ, POS(12)},            /* Baghdad Time */
 
164
        {"btt", TZ, POS(24)},           /* Bhutan Time */
 
165
        {"cadt", DTZ, POS(42)},         /* Central Australian DST */
 
166
        {"cast", TZ, POS(38)},          /* Central Australian ST */
 
167
        {"cat", TZ, NEG(40)},           /* Central Alaska Time */
 
168
        {"cct", TZ, POS(32)},           /* China Coast Time */
 
169
#if 0
 
170
        {"cct", TZ, POS(26)},           /* Indian Cocos (Island) Time */
 
171
#endif
 
172
        {"cdt", DTZ, NEG(20)},          /* Central Daylight Time */
 
173
        {"cest", DTZ, POS(8)},          /* Central European Dayl.Time */
 
174
        {"cet", TZ, POS(4)},            /* Central European Time */
 
175
        {"cetdst", DTZ, POS(8)},        /* Central European Dayl.Time */
 
176
        {"chadt", DTZ, POS(55)},        /* Chatham Island Daylight Time (13:45) */
 
177
        {"chast", TZ, POS(51)},         /* Chatham Island Time (12:45) */
 
178
#if 0
 
179
        ckhst
 
180
#endif
 
181
        {"ckt", TZ, POS(48)},           /* Cook Islands Time */
 
182
        {"clst", DTZ, NEG(12)},         /* Chile Summer Time */
 
183
        {"clt", TZ, NEG(16)},           /* Chile Time */
 
184
#if 0
 
185
        cost
 
186
#endif
 
187
        {"cot", TZ, NEG(20)},           /* Columbia Time */
 
188
        {"cst", TZ, NEG(24)},           /* Central Standard Time */
 
189
        {DCURRENT, RESERV, DTK_CURRENT},        /* "current" is always now */
 
190
#if 0
 
191
        cvst
 
192
#endif
 
193
        {"cvt", TZ, POS(28)},           /* Christmas Island Time (Indian Ocean) */
 
194
        {"cxt", TZ, POS(28)},           /* Christmas Island Time (Indian Ocean) */
 
195
        {"d", UNITS, DTK_DAY},          /* "day of month" for ISO input */
 
196
        {"davt", TZ, POS(28)},          /* Davis Time (Antarctica) */
 
197
        {"ddut", TZ, POS(40)},          /* Dumont-d'Urville Time (Antarctica) */
 
198
        {"dec", MONTH, 12},
 
199
        {"december", MONTH, 12},
 
200
        {"dnt", TZ, POS(4)},            /* Dansk Normal Tid */
 
201
        {"dow", RESERV, DTK_DOW},       /* day of week */
 
202
        {"doy", RESERV, DTK_DOY},       /* day of year */
 
203
        {"dst", DTZMOD, 6},
 
204
#if 0
 
205
        {"dusst", DTZ, POS(24)},        /* Dushanbe Summer Time */
 
206
#endif
 
207
        {"easst", DTZ, NEG(20)},        /* Easter Island Summer Time */
 
208
        {"east", TZ, NEG(24)},          /* Easter Island Time */
 
209
        {"eat", TZ, POS(12)},           /* East Africa Time */
 
210
#if 0
 
211
        {"east", DTZ, POS(16)},         /* Indian Antananarivo Savings Time */
 
212
        {"eat", TZ, POS(12)},           /* Indian Antananarivo Time */
 
213
        {"ect", TZ, NEG(16)},           /* Eastern Caribbean Time */
 
214
        {"ect", TZ, NEG(20)},           /* Ecuador Time */
 
215
#endif
 
216
        {"edt", DTZ, NEG(16)},          /* Eastern Daylight Time */
 
217
        {"eest", DTZ, POS(12)},         /* Eastern Europe Summer Time */
 
218
        {"eet", TZ, POS(8)},            /* East. Europe, USSR Zone 1 */
 
219
        {"eetdst", DTZ, POS(12)},       /* Eastern Europe Daylight Time */
 
220
        {"egst", DTZ, POS(0)},          /* East Greenland Summer Time */
 
221
        {"egt", TZ, NEG(4)},            /* East Greenland Time */
 
222
#if 0
 
223
        ehdt
 
224
#endif
 
225
        {EPOCH, RESERV, DTK_EPOCH}, /* "epoch" reserved for system epoch time */
 
226
        {"est", TZ, NEG(20)},           /* Eastern Standard Time */
 
227
        {"feb", MONTH, 2},
 
228
        {"february", MONTH, 2},
 
229
        {"fjst", DTZ, NEG(52)},         /* Fiji Summer Time (13 hour offset!) */
 
230
        {"fjt", TZ, NEG(48)},           /* Fiji Time */
 
231
        {"fkst", DTZ, NEG(12)},         /* Falkland Islands Summer Time */
 
232
        {"fkt", TZ, NEG(8)},            /* Falkland Islands Time */
 
233
        {"fnst", DTZ, NEG(4)},          /* Fernando de Noronha Summer Time */
 
234
        {"fnt", TZ, NEG(8)},            /* Fernando de Noronha Time */
 
235
        {"fri", DOW, 5},
 
236
        {"friday", DOW, 5},
 
237
        {"fst", TZ, POS(4)},            /* French Summer Time */
 
238
        {"fwt", DTZ, POS(8)},           /* French Winter Time  */
 
239
        {"galt", TZ, NEG(24)},          /* Galapagos Time */
 
240
        {"gamt", TZ, NEG(36)},          /* Gambier Time */
 
241
        {"gest", DTZ, POS(20)},         /* Georgia Summer Time */
 
242
        {"get", TZ, POS(16)},           /* Georgia Time */
 
243
        {"gft", TZ, NEG(12)},           /* French Guiana Time */
 
244
#if 0
 
245
        ghst
 
246
#endif
 
247
        {"gilt", TZ, POS(48)},          /* Gilbert Islands Time */
 
248
        {"gmt", TZ, POS(0)},            /* Greenwich Mean Time */
 
249
        {"gst", TZ, POS(40)},           /* Guam Std Time, USSR Zone 9 */
 
250
        {"gyt", TZ, NEG(16)},           /* Guyana Time */
 
251
        {"h", UNITS, DTK_HOUR},         /* "hour" */
 
252
#if 0
 
253
        hadt
 
254
        hast
 
255
#endif
 
256
        {"hdt", DTZ, NEG(36)},          /* Hawaii/Alaska Daylight Time */
 
257
#if 0
 
258
        hkst
 
259
#endif
 
260
        {"hkt", TZ, POS(32)},           /* Hong Kong Time */
 
261
#if 0
 
262
        {"hmt", TZ, POS(12)},           /* Hellas ? ? */
 
263
        hovst
 
264
        hovt
 
265
#endif
 
266
        {"hst", TZ, NEG(40)},           /* Hawaii Std Time */
 
267
#if 0
 
268
        hwt
 
269
#endif
 
270
        {"ict", TZ, POS(28)},           /* Indochina Time */
 
271
        {"idle", TZ, POS(48)},          /* Intl. Date Line, East */
 
272
        {"idlw", TZ, NEG(48)},          /* Intl. Date Line, West */
 
273
#if 0
 
274
        idt                                                     /* Israeli, Iran, Indian Daylight Time */
 
275
#endif
 
276
        {LATE, RESERV, DTK_LATE},       /* "infinity" reserved for "late time" */
 
277
        {INVALID, RESERV, DTK_INVALID},         /* "invalid" reserved for bad time */
 
278
        {"iot", TZ, POS(20)},           /* Indian Chagos Time */
 
279
        {"irkst", DTZ, POS(36)},        /* Irkutsk Summer Time */
 
280
        {"irkt", TZ, POS(32)},          /* Irkutsk Time */
 
281
        {"irt", TZ, POS(14)},           /* Iran Time */
 
282
#if 0
 
283
        isst
 
284
#endif
 
285
        {"ist", TZ, POS(8)},            /* Israel */
 
286
        {"it", TZ, POS(14)},            /* Iran Time */
 
287
        {"j", UNITS, DTK_JULIAN},
 
288
        {"jan", MONTH, 1},
 
289
        {"january", MONTH, 1},
 
290
        {"javt", TZ, POS(28)},          /* Java Time (07:00? see JT) */
 
291
        {"jayt", TZ, POS(36)},          /* Jayapura Time (Indonesia) */
 
292
        {"jd", UNITS, DTK_JULIAN},
 
293
        {"jst", TZ, POS(36)},           /* Japan Std Time,USSR Zone 8 */
 
294
        {"jt", TZ, POS(30)},            /* Java Time (07:30? see JAVT) */
 
295
        {"jul", MONTH, 7},
 
296
        {"julian", UNITS, DTK_JULIAN},
 
297
        {"july", MONTH, 7},
 
298
        {"jun", MONTH, 6},
 
299
        {"june", MONTH, 6},
 
300
        {"kdt", DTZ, POS(40)},          /* Korea Daylight Time */
 
301
        {"kgst", DTZ, POS(24)},         /* Kyrgyzstan Summer Time */
 
302
        {"kgt", TZ, POS(20)},           /* Kyrgyzstan Time */
 
303
        {"kost", TZ, POS(48)},          /* Kosrae Time */
 
304
        {"krast", DTZ, POS(28)},        /* Krasnoyarsk Summer Time */
 
305
        {"krat", TZ, POS(32)},          /* Krasnoyarsk Standard Time */
 
306
        {"kst", TZ, POS(36)},           /* Korea Standard Time */
 
307
        {"lhdt", DTZ, POS(44)},         /* Lord Howe Daylight Time, Australia */
 
308
        {"lhst", TZ, POS(42)},          /* Lord Howe Standard Time, Australia */
 
309
        {"ligt", TZ, POS(40)},          /* From Melbourne, Australia */
 
310
        {"lint", TZ, POS(56)},          /* Line Islands Time (Kiribati; +14
 
311
                                                                 * hours!) */
 
312
        {"lkt", TZ, POS(24)},           /* Lanka Time */
 
313
        {"m", UNITS, DTK_MONTH},        /* "month" for ISO input */
 
314
        {"magst", DTZ, POS(48)},        /* Magadan Summer Time */
 
315
        {"magt", TZ, POS(44)},          /* Magadan Time */
 
316
        {"mar", MONTH, 3},
 
317
        {"march", MONTH, 3},
 
318
        {"mart", TZ, NEG(38)},          /* Marquesas Time */
 
319
        {"mawt", TZ, POS(24)},          /* Mawson, Antarctica */
 
320
        {"may", MONTH, 5},
 
321
        {"mdt", DTZ, NEG(24)},          /* Mountain Daylight Time */
 
322
        {"mest", DTZ, POS(8)},          /* Middle Europe Summer Time */
 
323
        {"met", TZ, POS(4)},            /* Middle Europe Time */
 
324
        {"metdst", DTZ, POS(8)},        /* Middle Europe Daylight Time */
 
325
        {"mewt", TZ, POS(4)},           /* Middle Europe Winter Time */
 
326
        {"mez", TZ, POS(4)},            /* Middle Europe Zone */
 
327
        {"mht", TZ, POS(48)},           /* Kwajalein */
 
328
        {"mm", UNITS, DTK_MINUTE},      /* "minute" for ISO input */
 
329
        {"mmt", TZ, POS(26)},           /* Myanmar Time */
 
330
        {"mon", DOW, 1},
 
331
        {"monday", DOW, 1},
 
332
#if 0
 
333
        most
 
334
#endif
 
335
        {"mpt", TZ, POS(40)},           /* North Mariana Islands Time */
 
336
        {"msd", DTZ, POS(16)},          /* Moscow Summer Time */
 
337
        {"msk", TZ, POS(12)},           /* Moscow Time */
 
338
        {"mst", TZ, NEG(28)},           /* Mountain Standard Time */
 
339
        {"mt", TZ, POS(34)},            /* Moluccas Time */
 
340
        {"mut", TZ, POS(16)},           /* Mauritius Island Time */
 
341
        {"mvt", TZ, POS(20)},           /* Maldives Island Time */
 
342
        {"myt", TZ, POS(32)},           /* Malaysia Time */
 
343
#if 0
 
344
        ncst
 
345
#endif
 
346
        {"nct", TZ, POS(44)},           /* New Caledonia Time */
 
347
        {"ndt", DTZ, NEG(10)},          /* Nfld. Daylight Time */
 
348
        {"nft", TZ, NEG(14)},           /* Newfoundland Standard Time */
 
349
        {"nor", TZ, POS(4)},            /* Norway Standard Time */
 
350
        {"nov", MONTH, 11},
 
351
        {"november", MONTH, 11},
 
352
        {"novst", DTZ, POS(28)},        /* Novosibirsk Summer Time */
 
353
        {"novt", TZ, POS(24)},          /* Novosibirsk Standard Time */
 
354
        {NOW, RESERV, DTK_NOW},         /* current transaction time */
 
355
        {"npt", TZ, POS(23)},           /* Nepal Standard Time (GMT-5:45) */
 
356
        {"nst", TZ, NEG(14)},           /* Nfld. Standard Time */
 
357
        {"nt", TZ, NEG(44)},            /* Nome Time */
 
358
        {"nut", TZ, NEG(44)},           /* Niue Time */
 
359
        {"nzdt", DTZ, POS(52)},         /* New Zealand Daylight Time */
 
360
        {"nzst", TZ, POS(48)},          /* New Zealand Standard Time */
 
361
        {"nzt", TZ, POS(48)},           /* New Zealand Time */
 
362
        {"oct", MONTH, 10},
 
363
        {"october", MONTH, 10},
 
364
        {"omsst", DTZ, POS(28)},        /* Omsk Summer Time */
 
365
        {"omst", TZ, POS(24)},          /* Omsk Time */
 
366
        {"on", IGNORE_DTF, 0},          /* "on" (throwaway) */
 
367
        {"pdt", DTZ, NEG(28)},          /* Pacific Daylight Time */
 
368
#if 0
 
369
        pest
 
370
#endif
 
371
        {"pet", TZ, NEG(20)},           /* Peru Time */
 
372
        {"petst", DTZ, POS(52)},        /* Petropavlovsk-Kamchatski Summer Time */
 
373
        {"pett", TZ, POS(48)},          /* Petropavlovsk-Kamchatski Time */
 
374
        {"pgt", TZ, POS(40)},           /* Papua New Guinea Time */
 
375
        {"phot", TZ, POS(52)},          /* Phoenix Islands (Kiribati) Time */
 
376
#if 0
 
377
        phst
 
378
#endif
 
379
        {"pht", TZ, POS(32)},           /* Phillipine Time */
 
380
        {"pkt", TZ, POS(20)},           /* Pakistan Time */
 
381
        {"pm", AMPM, PM},
 
382
        {"pmdt", DTZ, NEG(8)},          /* Pierre & Miquelon Daylight Time */
 
383
#if 0
 
384
        pmst
 
385
#endif
 
386
        {"pont", TZ, POS(44)},          /* Ponape Time (Micronesia) */
 
387
        {"pst", TZ, NEG(32)},           /* Pacific Standard Time */
 
388
        {"pwt", TZ, POS(36)},           /* Palau Time */
 
389
        {"pyst", DTZ, NEG(12)},         /* Paraguay Summer Time */
 
390
        {"pyt", TZ, NEG(16)},           /* Paraguay Time */
 
391
        {"ret", DTZ, POS(16)},          /* Reunion Island Time */
 
392
        {"s", UNITS, DTK_SECOND},       /* "seconds" for ISO input */
 
393
        {"sadt", DTZ, POS(42)},         /* S. Australian Dayl. Time */
 
394
#if 0
 
395
        samst
 
396
        samt
 
397
#endif
 
398
        {"sast", TZ, POS(38)},          /* South Australian Std Time */
 
399
        {"sat", DOW, 6},
 
400
        {"saturday", DOW, 6},
 
401
#if 0
 
402
        sbt
 
403
#endif
 
404
        {"sct", DTZ, POS(16)},          /* Mahe Island Time */
 
405
        {"sep", MONTH, 9},
 
406
        {"sept", MONTH, 9},
 
407
        {"september", MONTH, 9},
 
408
        {"set", TZ, NEG(4)},            /* Seychelles Time ?? */
 
409
#if 0
 
410
        sgt
 
411
#endif
 
412
        {"sst", DTZ, POS(8)},           /* Swedish Summer Time */
 
413
        {"sun", DOW, 0},
 
414
        {"sunday", DOW, 0},
 
415
        {"swt", TZ, POS(4)},            /* Swedish Winter Time */
 
416
#if 0
 
417
        syot
 
418
#endif
 
419
        {"t", ISOTIME, DTK_TIME},       /* Filler for ISO time fields */
 
420
        {"tft", TZ, POS(20)},           /* Kerguelen Time */
 
421
        {"that", TZ, NEG(40)},          /* Tahiti Time */
 
422
        {"thu", DOW, 4},
 
423
        {"thur", DOW, 4},
 
424
        {"thurs", DOW, 4},
 
425
        {"thursday", DOW, 4},
 
426
        {"tjt", TZ, POS(20)},           /* Tajikistan Time */
 
427
        {"tkt", TZ, NEG(40)},           /* Tokelau Time */
 
428
        {"tmt", TZ, POS(20)},           /* Turkmenistan Time */
 
429
        {TODAY, RESERV, DTK_TODAY}, /* midnight */
 
430
        {TOMORROW, RESERV, DTK_TOMORROW},       /* tomorrow midnight */
 
431
#if 0
 
432
        tost
 
433
#endif
 
434
        {"tot", TZ, POS(52)},           /* Tonga Time */
 
435
#if 0
 
436
        tpt
 
437
#endif
 
438
        {"truk", TZ, POS(40)},          /* Truk Time */
 
439
        {"tue", DOW, 2},
 
440
        {"tues", DOW, 2},
 
441
        {"tuesday", DOW, 2},
 
442
        {"tvt", TZ, POS(48)},           /* Tuvalu Time */
 
443
#if 0
 
444
        uct
 
445
#endif
 
446
        {"ulast", DTZ, POS(36)},        /* Ulan Bator Summer Time */
 
447
        {"ulat", TZ, POS(32)},          /* Ulan Bator Time */
 
448
        {"undefined", RESERV, DTK_INVALID}, /* pre-v6.1 invalid time */
 
449
        {"ut", TZ, POS(0)},
 
450
        {"utc", TZ, POS(0)},
 
451
        {"uyst", DTZ, NEG(8)},          /* Uruguay Summer Time */
 
452
        {"uyt", TZ, NEG(12)},           /* Uruguay Time */
 
453
        {"uzst", DTZ, POS(24)},         /* Uzbekistan Summer Time */
 
454
        {"uzt", TZ, POS(20)},           /* Uzbekistan Time */
 
455
        {"vet", TZ, NEG(16)},           /* Venezuela Time */
 
456
        {"vlast", DTZ, POS(44)},        /* Vladivostok Summer Time */
 
457
        {"vlat", TZ, POS(40)},          /* Vladivostok Time */
 
458
#if 0
 
459
        vust
 
460
#endif
 
461
        {"vut", TZ, POS(44)},           /* Vanuata Time */
 
462
        {"wadt", DTZ, POS(32)},         /* West Australian DST */
 
463
        {"wakt", TZ, POS(48)},          /* Wake Time */
 
464
#if 0
 
465
        warst
 
466
#endif
 
467
        {"wast", TZ, POS(28)},          /* West Australian Std Time */
 
468
        {"wat", TZ, NEG(4)},            /* West Africa Time */
 
469
        {"wdt", DTZ, POS(36)},          /* West Australian DST */
 
470
        {"wed", DOW, 3},
 
471
        {"wednesday", DOW, 3},
 
472
        {"weds", DOW, 3},
 
473
        {"west", DTZ, POS(4)},          /* Western Europe Summer Time */
 
474
        {"wet", TZ, POS(0)},            /* Western Europe */
 
475
        {"wetdst", DTZ, POS(4)},        /* Western Europe Daylight Savings Time */
 
476
        {"wft", TZ, POS(48)},           /* Wallis and Futuna Time */
 
477
        {"wgst", DTZ, NEG(8)},          /* West Greenland Summer Time */
 
478
        {"wgt", TZ, NEG(12)},           /* West Greenland Time */
 
479
        {"wst", TZ, POS(32)},           /* West Australian Standard Time */
 
480
        {"y", UNITS, DTK_YEAR},         /* "year" for ISO input */
 
481
        {"yakst", DTZ, POS(40)},        /* Yakutsk Summer Time */
 
482
        {"yakt", TZ, POS(36)},          /* Yakutsk Time */
 
483
        {"yapt", TZ, POS(40)},          /* Yap Time (Micronesia) */
 
484
        {"ydt", DTZ, NEG(32)},          /* Yukon Daylight Time */
 
485
        {"yekst", DTZ, POS(24)},        /* Yekaterinburg Summer Time */
 
486
        {"yekt", TZ, POS(20)},          /* Yekaterinburg Time */
 
487
        {YESTERDAY, RESERV, DTK_YESTERDAY}, /* yesterday midnight */
 
488
        {"yst", TZ, NEG(36)},           /* Yukon Standard Time */
 
489
        {"z", TZ, POS(0)},                      /* time zone tag per ISO-8601 */
 
490
        {"zp4", TZ, NEG(16)},           /* UTC +4  hours. */
 
491
        {"zp5", TZ, NEG(20)},           /* UTC +5  hours. */
 
492
        {"zp6", TZ, NEG(24)},           /* UTC +6  hours. */
 
493
        {ZULU, TZ, POS(0)},                     /* UTC */
 
494
};
 
495
 
 
496
static unsigned int szdatetktbl = sizeof datetktbl / sizeof datetktbl[0];
 
497
 
 
498
/* Used for SET australian_timezones to override North American ones */
 
499
static datetkn australian_datetktbl[] = {
 
500
        {"acst", TZ, POS(38)},          /* Cent. Australia */
 
501
        {"cst", TZ, POS(42)},           /* Australia Central Std Time */
 
502
        {"east", TZ, POS(40)},          /* East Australian Std Time */
 
503
        {"est", TZ, POS(40)},           /* Australia Eastern Std Time */
 
504
        {"sat", TZ, POS(38)},
 
505
};
 
506
 
 
507
static unsigned int australian_szdatetktbl = sizeof australian_datetktbl /
 
508
sizeof australian_datetktbl[0];
 
509
 
 
510
static datetkn deltatktbl[] = {
 
511
        /* text, token, lexval */
 
512
        {"@", IGNORE_DTF, 0},           /* postgres relative prefix */
 
513
        {DAGO, AGO, 0},                         /* "ago" indicates negative time offset */
 
514
        {"c", UNITS, DTK_CENTURY},      /* "century" relative */
 
515
        {"cent", UNITS, DTK_CENTURY},           /* "century" relative */
 
516
        {"centuries", UNITS, DTK_CENTURY},      /* "centuries" relative */
 
517
        {DCENTURY, UNITS, DTK_CENTURY},         /* "century" relative */
 
518
        {"d", UNITS, DTK_DAY},          /* "day" relative */
 
519
        {DDAY, UNITS, DTK_DAY},         /* "day" relative */
 
520
        {"days", UNITS, DTK_DAY},       /* "days" relative */
 
521
        {"dec", UNITS, DTK_DECADE}, /* "decade" relative */
 
522
        {DDECADE, UNITS, DTK_DECADE},           /* "decade" relative */
 
523
        {"decades", UNITS, DTK_DECADE},         /* "decades" relative */
 
524
        {"decs", UNITS, DTK_DECADE},    /* "decades" relative */
 
525
        {"h", UNITS, DTK_HOUR},         /* "hour" relative */
 
526
        {DHOUR, UNITS, DTK_HOUR},       /* "hour" relative */
 
527
        {"hours", UNITS, DTK_HOUR}, /* "hours" relative */
 
528
        {"hr", UNITS, DTK_HOUR},        /* "hour" relative */
 
529
        {"hrs", UNITS, DTK_HOUR},       /* "hours" relative */
 
530
        {INVALID, RESERV, DTK_INVALID},         /* reserved for invalid time */
 
531
        {"m", UNITS, DTK_MINUTE},       /* "minute" relative */
 
532
        {"microsecon", UNITS, DTK_MICROSEC},            /* "microsecond" relative */
 
533
        {"mil", UNITS, DTK_MILLENNIUM},         /* "millennium" relative */
 
534
        {"millennia", UNITS, DTK_MILLENNIUM},           /* "millennia" relative */
 
535
        {DMILLENNIUM, UNITS, DTK_MILLENNIUM},           /* "millennium" relative */
 
536
        {"millisecon", UNITS, DTK_MILLISEC},            /* relative */
 
537
        {"mils", UNITS, DTK_MILLENNIUM},        /* "millennia" relative */
 
538
        {"min", UNITS, DTK_MINUTE}, /* "minute" relative */
 
539
        {"mins", UNITS, DTK_MINUTE},    /* "minutes" relative */
 
540
        {DMINUTE, UNITS, DTK_MINUTE},           /* "minute" relative */
 
541
        {"minutes", UNITS, DTK_MINUTE},         /* "minutes" relative */
 
542
        {"mon", UNITS, DTK_MONTH},      /* "months" relative */
 
543
        {"mons", UNITS, DTK_MONTH}, /* "months" relative */
 
544
        {DMONTH, UNITS, DTK_MONTH}, /* "month" relative */
 
545
        {"months", UNITS, DTK_MONTH},
 
546
        {"ms", UNITS, DTK_MILLISEC},
 
547
        {"msec", UNITS, DTK_MILLISEC},
 
548
        {DMILLISEC, UNITS, DTK_MILLISEC},
 
549
        {"mseconds", UNITS, DTK_MILLISEC},
 
550
        {"msecs", UNITS, DTK_MILLISEC},
 
551
        {"qtr", UNITS, DTK_QUARTER},    /* "quarter" relative */
 
552
        {DQUARTER, UNITS, DTK_QUARTER},         /* "quarter" relative */
 
553
        {"reltime", IGNORE_DTF, 0}, /* pre-v6.1 "Undefined Reltime" */
 
554
        {"s", UNITS, DTK_SECOND},
 
555
        {"sec", UNITS, DTK_SECOND},
 
556
        {DSECOND, UNITS, DTK_SECOND},
 
557
        {"seconds", UNITS, DTK_SECOND},
 
558
        {"secs", UNITS, DTK_SECOND},
 
559
        {DTIMEZONE, UNITS, DTK_TZ}, /* "timezone" time offset */
 
560
        {"timezone_h", UNITS, DTK_TZ_HOUR}, /* timezone hour units */
 
561
        {"timezone_m", UNITS, DTK_TZ_MINUTE},           /* timezone minutes units */
 
562
        {"undefined", RESERV, DTK_INVALID}, /* pre-v6.1 invalid time */
 
563
        {"us", UNITS, DTK_MICROSEC},    /* "microsecond" relative */
 
564
        {"usec", UNITS, DTK_MICROSEC},          /* "microsecond" relative */
 
565
        {DMICROSEC, UNITS, DTK_MICROSEC},       /* "microsecond" relative */
 
566
        {"useconds", UNITS, DTK_MICROSEC},      /* "microseconds" relative */
 
567
        {"usecs", UNITS, DTK_MICROSEC},         /* "microseconds" relative */
 
568
        {"w", UNITS, DTK_WEEK},         /* "week" relative */
 
569
        {DWEEK, UNITS, DTK_WEEK},       /* "week" relative */
 
570
        {"weeks", UNITS, DTK_WEEK}, /* "weeks" relative */
 
571
        {"y", UNITS, DTK_YEAR},         /* "year" relative */
 
572
        {DYEAR, UNITS, DTK_YEAR},       /* "year" relative */
 
573
        {"years", UNITS, DTK_YEAR}, /* "years" relative */
 
574
        {"yr", UNITS, DTK_YEAR},        /* "year" relative */
 
575
        {"yrs", UNITS, DTK_YEAR},       /* "years" relative */
 
576
};
 
577
 
 
578
static unsigned int szdeltatktbl = sizeof deltatktbl / sizeof deltatktbl[0];
 
579
 
 
580
static datetkn *datecache[MAXDATEFIELDS] = {NULL};
 
581
 
 
582
static datetkn *deltacache[MAXDATEFIELDS] = {NULL};
 
583
 
 
584
 
 
585
/*
 
586
 * Calendar time to Julian date conversions.
 
587
 * Julian date is commonly used in astronomical applications,
 
588
 *      since it is numerically accurate and computationally simple.
 
589
 * The algorithms here will accurately convert between Julian day
 
590
 *      and calendar date for all non-negative Julian days
 
591
 *      (i.e. from Nov 24, -4713 on).
 
592
 *
 
593
 * These routines will be used by other date/time packages
 
594
 * - thomas 97/02/25
 
595
 *
 
596
 * Rewritten to eliminate overflow problems. This now allows the
 
597
 * routines to work correctly for all Julian day counts from
 
598
 * 0 to 2147483647      (Nov 24, -4713 to Jun 3, 5874898) assuming
 
599
 * a 32-bit integer. Longer types should also work to the limits
 
600
 * of their precision.
 
601
 */
 
602
 
 
603
int
 
604
date2j(int y, int m, int d)
 
605
{
 
606
        int                     julian;
 
607
        int                     century;
 
608
 
 
609
        if (m > 2)
 
610
        {
 
611
                m += 1;
 
612
                y += 4800;
 
613
        }
 
614
        else
 
615
        {
 
616
                m += 13;
 
617
                y += 4799;
 
618
        }
 
619
 
 
620
        century = y / 100;
 
621
        julian = y * 365 - 32167;
 
622
        julian += y / 4 - century + century / 4;
 
623
        julian += 7834 * m / 256 + d;
 
624
 
 
625
        return julian;
 
626
}       /* date2j() */
 
627
 
 
628
void
 
629
j2date(int jd, int *year, int *month, int *day)
 
630
{
 
631
        unsigned int julian;
 
632
        unsigned int quad;
 
633
        unsigned int extra;
 
634
        int                     y;
 
635
 
 
636
        julian = jd;
 
637
        julian += 32044;
 
638
        quad = julian / 146097;
 
639
        extra = (julian - quad * 146097) * 4 + 3;
 
640
        julian += 60 + quad * 3 + extra / 146097;
 
641
        quad = julian / 1461;
 
642
        julian -= quad * 1461;
 
643
        y = julian * 4 / 1461;
 
644
        julian = ((y != 0) ? ((julian + 305) % 365) : ((julian + 306) % 366))
 
645
                + 123;
 
646
        y += quad * 4;
 
647
        *year = y - 4800;
 
648
        quad = julian * 2141 / 65536;
 
649
        *day = julian - 7834 * quad / 256;
 
650
        *month = (quad + 10) % 12 + 1;
 
651
 
 
652
        return;
 
653
}       /* j2date() */
 
654
 
 
655
 
 
656
/*
 
657
 * j2day - convert Julian date to day-of-week (0..6 == Sun..Sat)
 
658
 *
 
659
 * Note: various places use the locution j2day(date - 1) to produce a
 
660
 * result according to the convention 0..6 = Mon..Sun.  This is a bit of
 
661
 * a crock, but will work as long as the computation here is just a modulo.
 
662
 */
 
663
int
 
664
j2day(int date)
 
665
{
 
666
        unsigned int day;
 
667
 
 
668
        day = date;
 
669
 
 
670
        day += 1;
 
671
        day %= 7;
 
672
 
 
673
        return (int) day;
 
674
}       /* j2day() */
 
675
 
 
676
 
 
677
/* TrimTrailingZeros()
 
678
 * ... resulting from printing numbers with full precision.
 
679
 */
 
680
static void
 
681
TrimTrailingZeros(char *str)
 
682
{
 
683
        int                     len = strlen(str);
 
684
 
 
685
#if 0
 
686
        /* chop off trailing one to cope with interval rounding */
 
687
        if (strcmp((str + len - 4), "0001") == 0)
 
688
        {
 
689
                len -= 4;
 
690
                *(str + len) = '\0';
 
691
        }
 
692
#endif
 
693
 
 
694
        /* chop off trailing zeros... but leave at least 2 fractional digits */
 
695
        while ((*(str + len - 1) == '0')
 
696
                   && (*(str + len - 3) != '.'))
 
697
        {
 
698
                len--;
 
699
                *(str + len) = '\0';
 
700
        }
 
701
}
 
702
 
 
703
 
 
704
/* ParseDateTime()
 
705
 *      Break string into tokens based on a date/time context.
 
706
 *      Returns 0 if successful, DTERR code if bogus input detected.
 
707
 *
 
708
 * timestr - the input string
 
709
 * lowstr - workspace for field string storage (must be large enough for
 
710
 *              a copy of the input string, including trailing null)
 
711
 * field[] - pointers to field strings are returned in this array
 
712
 * ftype[] - field type indicators are returned in this array
 
713
 * maxfields - dimensions of the above two arrays
 
714
 * *numfields - set to the actual number of fields detected
 
715
 *
 
716
 * The fields extracted from the input are stored as separate, null-terminated
 
717
 * strings in the workspace at lowstr.  Any text is converted to lower case.
 
718
 *
 
719
 * Several field types are assigned:
 
720
 *      DTK_NUMBER - digits and (possibly) a decimal point
 
721
 *      DTK_DATE - digits and two delimiters, or digits and text
 
722
 *      DTK_TIME - digits, colon delimiters, and possibly a decimal point
 
723
 *      DTK_STRING - text (no digits)
 
724
 *      DTK_SPECIAL - leading "+" or "-" followed by text
 
725
 *      DTK_TZ - leading "+" or "-" followed by digits
 
726
 *
 
727
 * Note that some field types can hold unexpected items:
 
728
 *      DTK_NUMBER can hold date fields (yy.ddd)
 
729
 *      DTK_STRING can hold months (January) and time zones (PST)
 
730
 *      DTK_DATE can hold Posix time zones (GMT-8)
 
731
 */
 
732
int
 
733
ParseDateTime(const char *timestr, char *lowstr,
 
734
                          char **field, int *ftype, int maxfields, int *numfields)
 
735
{
 
736
        int                     nf = 0;
 
737
        const char *cp = timestr;
 
738
        char       *lp = lowstr;
 
739
 
 
740
        /* outer loop through fields */
 
741
        while (*cp != '\0')
 
742
        {
 
743
                /* Ignore spaces between fields */
 
744
                if (isspace((unsigned char) *cp))
 
745
                {
 
746
                        cp++;
 
747
                        continue;
 
748
                }
 
749
 
 
750
                /* Record start of current field */
 
751
                if (nf >= maxfields)
 
752
                        return DTERR_BAD_FORMAT;
 
753
                field[nf] = lp;
 
754
 
 
755
                /* leading digit? then date or time */
 
756
                if (isdigit((unsigned char) *cp))
 
757
                {
 
758
                        *lp++ = *cp++;
 
759
                        while (isdigit((unsigned char) *cp))
 
760
                                *lp++ = *cp++;
 
761
 
 
762
                        /* time field? */
 
763
                        if (*cp == ':')
 
764
                        {
 
765
                                ftype[nf] = DTK_TIME;
 
766
                                *lp++ = *cp++;
 
767
                                while (isdigit((unsigned char) *cp) ||
 
768
                                           (*cp == ':') || (*cp == '.'))
 
769
                                        *lp++ = *cp++;
 
770
                        }
 
771
                        /* date field? allow embedded text month */
 
772
                        else if ((*cp == '-') || (*cp == '/') || (*cp == '.'))
 
773
                        {
 
774
                                /* save delimiting character to use later */
 
775
                                char            delim = *cp;
 
776
 
 
777
                                *lp++ = *cp++;
 
778
                                /* second field is all digits? then no embedded text month */
 
779
                                if (isdigit((unsigned char) *cp))
 
780
                                {
 
781
                                        ftype[nf] = ((delim == '.') ? DTK_NUMBER : DTK_DATE);
 
782
                                        while (isdigit((unsigned char) *cp))
 
783
                                                *lp++ = *cp++;
 
784
 
 
785
                                        /*
 
786
                                         * insist that the delimiters match to get a
 
787
                                         * three-field date.
 
788
                                         */
 
789
                                        if (*cp == delim)
 
790
                                        {
 
791
                                                ftype[nf] = DTK_DATE;
 
792
                                                *lp++ = *cp++;
 
793
                                                while (isdigit((unsigned char) *cp) || (*cp == delim))
 
794
                                                        *lp++ = *cp++;
 
795
                                        }
 
796
                                }
 
797
                                else
 
798
                                {
 
799
                                        ftype[nf] = DTK_DATE;
 
800
                                        while (isalnum((unsigned char) *cp) || (*cp == delim))
 
801
                                                *lp++ = pg_tolower((unsigned char) *cp++);
 
802
                                }
 
803
                        }
 
804
 
 
805
                        /*
 
806
                         * otherwise, number only and will determine year, month, day,
 
807
                         * or concatenated fields later...
 
808
                         */
 
809
                        else
 
810
                                ftype[nf] = DTK_NUMBER;
 
811
                }
 
812
                /* Leading decimal point? Then fractional seconds... */
 
813
                else if (*cp == '.')
 
814
                {
 
815
                        *lp++ = *cp++;
 
816
                        while (isdigit((unsigned char) *cp))
 
817
                                *lp++ = *cp++;
 
818
 
 
819
                        ftype[nf] = DTK_NUMBER;
 
820
                }
 
821
 
 
822
                /*
 
823
                 * text? then date string, month, day of week, special, or
 
824
                 * timezone
 
825
                 */
 
826
                else if (isalpha((unsigned char) *cp))
 
827
                {
 
828
                        ftype[nf] = DTK_STRING;
 
829
                        *lp++ = pg_tolower((unsigned char) *cp++);
 
830
                        while (isalpha((unsigned char) *cp))
 
831
                                *lp++ = pg_tolower((unsigned char) *cp++);
 
832
 
 
833
                        /*
 
834
                         * Full date string with leading text month? Could also be a
 
835
                         * POSIX time zone...
 
836
                         */
 
837
                        if ((*cp == '-') || (*cp == '/') || (*cp == '.'))
 
838
                        {
 
839
                                char            delim = *cp;
 
840
 
 
841
                                ftype[nf] = DTK_DATE;
 
842
                                *lp++ = *cp++;
 
843
                                while (isdigit((unsigned char) *cp) || (*cp == delim))
 
844
                                        *lp++ = *cp++;
 
845
                        }
 
846
                }
 
847
                /* sign? then special or numeric timezone */
 
848
                else if ((*cp == '+') || (*cp == '-'))
 
849
                {
 
850
                        *lp++ = *cp++;
 
851
                        /* soak up leading whitespace */
 
852
                        while (isspace((unsigned char) *cp))
 
853
                                cp++;
 
854
                        /* numeric timezone? */
 
855
                        if (isdigit((unsigned char) *cp))
 
856
                        {
 
857
                                ftype[nf] = DTK_TZ;
 
858
                                *lp++ = *cp++;
 
859
                                while (isdigit((unsigned char) *cp) ||
 
860
                                           (*cp == ':') || (*cp == '.'))
 
861
                                        *lp++ = *cp++;
 
862
                        }
 
863
                        /* special? */
 
864
                        else if (isalpha((unsigned char) *cp))
 
865
                        {
 
866
                                ftype[nf] = DTK_SPECIAL;
 
867
                                *lp++ = pg_tolower((unsigned char) *cp++);
 
868
                                while (isalpha((unsigned char) *cp))
 
869
                                        *lp++ = pg_tolower((unsigned char) *cp++);
 
870
                        }
 
871
                        /* otherwise something wrong... */
 
872
                        else
 
873
                                return DTERR_BAD_FORMAT;
 
874
                }
 
875
                /* ignore other punctuation but use as delimiter */
 
876
                else if (ispunct((unsigned char) *cp))
 
877
                {
 
878
                        cp++;
 
879
                        continue;
 
880
                }
 
881
                /* otherwise, something is not right... */
 
882
                else
 
883
                        return DTERR_BAD_FORMAT;
 
884
 
 
885
                /* force in a delimiter after each field */
 
886
                *lp++ = '\0';
 
887
                nf++;
 
888
        }
 
889
 
 
890
        *numfields = nf;
 
891
 
 
892
        return 0;
 
893
}
 
894
 
 
895
 
 
896
/* DecodeDateTime()
 
897
 * Interpret previously parsed fields for general date and time.
 
898
 * Return 0 if full date, 1 if only time, and negative DTERR code if problems.
 
899
 * (Currently, all callers treat 1 as an error return too.)
 
900
 *
 
901
 *              External format(s):
 
902
 *                              "<weekday> <month>-<day>-<year> <hour>:<minute>:<second>"
 
903
 *                              "Fri Feb-7-1997 15:23:27"
 
904
 *                              "Feb-7-1997 15:23:27"
 
905
 *                              "2-7-1997 15:23:27"
 
906
 *                              "1997-2-7 15:23:27"
 
907
 *                              "1997.038 15:23:27"             (day of year 1-366)
 
908
 *              Also supports input in compact time:
 
909
 *                              "970207 152327"
 
910
 *                              "97038 152327"
 
911
 *                              "20011225T040506.789-07"
 
912
 *
 
913
 * Use the system-provided functions to get the current time zone
 
914
 *      if not specified in the input string.
 
915
 * If the date is outside the time_t system-supported time range,
 
916
 *      then assume UTC time zone. - thomas 1997-05-27
 
917
 */
 
918
int
 
919
DecodeDateTime(char **field, int *ftype, int nf,
 
920
                           int *dtype, struct pg_tm * tm, fsec_t *fsec, int *tzp)
 
921
{
 
922
        int                     fmask = 0,
 
923
                                tmask,
 
924
                                type;
 
925
        int                     ptype = 0;              /* "prefix type" for ISO y2001m02d04
 
926
                                                                 * format */
 
927
        int                     i;
 
928
        int                     val;
 
929
        int                     dterr;
 
930
        int                     mer = HR24;
 
931
        bool            haveTextMonth = FALSE;
 
932
        int                     is2digits = FALSE;
 
933
        int                     bc = FALSE;
 
934
 
 
935
        /*
 
936
         * We'll insist on at least all of the date fields, but initialize the
 
937
         * remaining fields in case they are not set later...
 
938
         */
 
939
        *dtype = DTK_DATE;
 
940
        tm->tm_hour = 0;
 
941
        tm->tm_min = 0;
 
942
        tm->tm_sec = 0;
 
943
        *fsec = 0;
 
944
        /* don't know daylight savings time status apriori */
 
945
        tm->tm_isdst = -1;
 
946
        if (tzp != NULL)
 
947
                *tzp = 0;
 
948
 
 
949
        for (i = 0; i < nf; i++)
 
950
        {
 
951
                switch (ftype[i])
 
952
                {
 
953
                        case DTK_DATE:
 
954
                                /***
 
955
                                 * Integral julian day with attached time zone?
 
956
                                 * All other forms with JD will be separated into
 
957
                                 * distinct fields, so we handle just this case here.
 
958
                                 ***/
 
959
                                if (ptype == DTK_JULIAN)
 
960
                                {
 
961
                                        char       *cp;
 
962
                                        int                     val;
 
963
 
 
964
                                        if (tzp == NULL)
 
965
                                                return DTERR_BAD_FORMAT;
 
966
 
 
967
                                        val = strtol(field[i], &cp, 10);
 
968
 
 
969
                                        j2date(val, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
 
970
                                        /* Get the time zone from the end of the string */
 
971
                                        dterr = DecodeTimezone(cp, tzp);
 
972
                                        if (dterr)
 
973
                                                return dterr;
 
974
 
 
975
                                        tmask = DTK_DATE_M | DTK_TIME_M | DTK_M(TZ);
 
976
                                        ptype = 0;
 
977
                                        break;
 
978
                                }
 
979
                                /***
 
980
                                 * Already have a date? Then this might be a POSIX time
 
981
                                 * zone with an embedded dash (e.g. "PST-3" == "EST") or
 
982
                                 * a run-together time with trailing time zone (e.g. hhmmss-zz).
 
983
                                 * - thomas 2001-12-25
 
984
                                 ***/
 
985
                                else if (((fmask & DTK_DATE_M) == DTK_DATE_M)
 
986
                                                 || (ptype != 0))
 
987
                                {
 
988
                                        /* No time zone accepted? Then quit... */
 
989
                                        if (tzp == NULL)
 
990
                                                return DTERR_BAD_FORMAT;
 
991
 
 
992
                                        if (isdigit((unsigned char) *field[i]) || ptype != 0)
 
993
                                        {
 
994
                                                char       *cp;
 
995
 
 
996
                                                if (ptype != 0)
 
997
                                                {
 
998
                                                        /* Sanity check; should not fail this test */
 
999
                                                        if (ptype != DTK_TIME)
 
1000
                                                                return DTERR_BAD_FORMAT;
 
1001
                                                        ptype = 0;
 
1002
                                                }
 
1003
 
 
1004
                                                /*
 
1005
                                                 * Starts with a digit but we already have a time
 
1006
                                                 * field? Then we are in trouble with a date and
 
1007
                                                 * time already...
 
1008
                                                 */
 
1009
                                                if ((fmask & DTK_TIME_M) == DTK_TIME_M)
 
1010
                                                        return DTERR_BAD_FORMAT;
 
1011
 
 
1012
                                                if ((cp = strchr(field[i], '-')) == NULL)
 
1013
                                                        return DTERR_BAD_FORMAT;
 
1014
 
 
1015
                                                /* Get the time zone from the end of the string */
 
1016
                                                dterr = DecodeTimezone(cp, tzp);
 
1017
                                                if (dterr)
 
1018
                                                        return dterr;
 
1019
                                                *cp = '\0';
 
1020
 
 
1021
                                                /*
 
1022
                                                 * Then read the rest of the field as a
 
1023
                                                 * concatenated time
 
1024
                                                 */
 
1025
                                                dterr = DecodeNumberField(strlen(field[i]), field[i],
 
1026
                                                                                                  fmask,
 
1027
                                                                                                  &tmask, tm,
 
1028
                                                                                                  fsec, &is2digits);
 
1029
                                                if (dterr < 0)
 
1030
                                                        return dterr;
 
1031
                                                ftype[i] = dterr;
 
1032
 
 
1033
                                                /*
 
1034
                                                 * modify tmask after returning from
 
1035
                                                 * DecodeNumberField()
 
1036
                                                 */
 
1037
                                                tmask |= DTK_M(TZ);
 
1038
                                        }
 
1039
                                        else
 
1040
                                        {
 
1041
                                                dterr = DecodePosixTimezone(field[i], tzp);
 
1042
                                                if (dterr)
 
1043
                                                        return dterr;
 
1044
 
 
1045
                                                ftype[i] = DTK_TZ;
 
1046
                                                tmask = DTK_M(TZ);
 
1047
                                        }
 
1048
                                }
 
1049
                                else
 
1050
                                {
 
1051
                                        dterr = DecodeDate(field[i], fmask, &tmask, tm);
 
1052
                                        if (dterr)
 
1053
                                                return dterr;
 
1054
                                }
 
1055
                                break;
 
1056
 
 
1057
                        case DTK_TIME:
 
1058
                                dterr = DecodeTime(field[i], fmask, &tmask, tm, fsec);
 
1059
                                if (dterr)
 
1060
                                        return dterr;
 
1061
 
 
1062
                                /*
 
1063
                                 * Check upper limit on hours; other limits checked in
 
1064
                                 * DecodeTime()
 
1065
                                 */
 
1066
                                if (tm->tm_hour > 23)
 
1067
                                        return DTERR_FIELD_OVERFLOW;
 
1068
                                break;
 
1069
 
 
1070
                        case DTK_TZ:
 
1071
                                {
 
1072
                                        int                     tz;
 
1073
 
 
1074
                                        if (tzp == NULL)
 
1075
                                                return DTERR_BAD_FORMAT;
 
1076
 
 
1077
                                        dterr = DecodeTimezone(field[i], &tz);
 
1078
                                        if (dterr)
 
1079
                                                return dterr;
 
1080
 
 
1081
                                        /*
 
1082
                                         * Already have a time zone? Then maybe this is the
 
1083
                                         * second field of a POSIX time: EST+3 (equivalent to
 
1084
                                         * PST)
 
1085
                                         */
 
1086
                                        if ((i > 0) && ((fmask & DTK_M(TZ)) != 0)
 
1087
                                                && (ftype[i - 1] == DTK_TZ)
 
1088
                                                && (isalpha((unsigned char) *field[i - 1])))
 
1089
                                        {
 
1090
                                                *tzp -= tz;
 
1091
                                                tmask = 0;
 
1092
                                        }
 
1093
                                        else
 
1094
                                        {
 
1095
                                                *tzp = tz;
 
1096
                                                tmask = DTK_M(TZ);
 
1097
                                        }
 
1098
                                }
 
1099
                                break;
 
1100
 
 
1101
                        case DTK_NUMBER:
 
1102
 
 
1103
                                /*
 
1104
                                 * Was this an "ISO date" with embedded field labels? An
 
1105
                                 * example is "y2001m02d04" - thomas 2001-02-04
 
1106
                                 */
 
1107
                                if (ptype != 0)
 
1108
                                {
 
1109
                                        char       *cp;
 
1110
                                        int                     val;
 
1111
 
 
1112
                                        val = strtol(field[i], &cp, 10);
 
1113
 
 
1114
                                        /*
 
1115
                                         * only a few kinds are allowed to have an embedded
 
1116
                                         * decimal
 
1117
                                         */
 
1118
                                        if (*cp == '.')
 
1119
                                                switch (ptype)
 
1120
                                                {
 
1121
                                                        case DTK_JULIAN:
 
1122
                                                        case DTK_TIME:
 
1123
                                                        case DTK_SECOND:
 
1124
                                                                break;
 
1125
                                                        default:
 
1126
                                                                return DTERR_BAD_FORMAT;
 
1127
                                                                break;
 
1128
                                                }
 
1129
                                        else if (*cp != '\0')
 
1130
                                                return DTERR_BAD_FORMAT;
 
1131
 
 
1132
                                        switch (ptype)
 
1133
                                        {
 
1134
                                                case DTK_YEAR:
 
1135
                                                        tm->tm_year = val;
 
1136
                                                        tmask = DTK_M(YEAR);
 
1137
                                                        break;
 
1138
 
 
1139
                                                case DTK_MONTH:
 
1140
 
 
1141
                                                        /*
 
1142
                                                         * already have a month and hour? then assume
 
1143
                                                         * minutes
 
1144
                                                         */
 
1145
                                                        if (((fmask & DTK_M(MONTH)) != 0)
 
1146
                                                                && ((fmask & DTK_M(HOUR)) != 0))
 
1147
                                                        {
 
1148
                                                                tm->tm_min = val;
 
1149
                                                                tmask = DTK_M(MINUTE);
 
1150
                                                        }
 
1151
                                                        else
 
1152
                                                        {
 
1153
                                                                tm->tm_mon = val;
 
1154
                                                                tmask = DTK_M(MONTH);
 
1155
                                                        }
 
1156
                                                        break;
 
1157
 
 
1158
                                                case DTK_DAY:
 
1159
                                                        tm->tm_mday = val;
 
1160
                                                        tmask = DTK_M(DAY);
 
1161
                                                        break;
 
1162
 
 
1163
                                                case DTK_HOUR:
 
1164
                                                        tm->tm_hour = val;
 
1165
                                                        tmask = DTK_M(HOUR);
 
1166
                                                        break;
 
1167
 
 
1168
                                                case DTK_MINUTE:
 
1169
                                                        tm->tm_min = val;
 
1170
                                                        tmask = DTK_M(MINUTE);
 
1171
                                                        break;
 
1172
 
 
1173
                                                case DTK_SECOND:
 
1174
                                                        tm->tm_sec = val;
 
1175
                                                        tmask = DTK_M(SECOND);
 
1176
                                                        if (*cp == '.')
 
1177
                                                        {
 
1178
                                                                double          frac;
 
1179
 
 
1180
                                                                frac = strtod(cp, &cp);
 
1181
                                                                if (*cp != '\0')
 
1182
                                                                        return DTERR_BAD_FORMAT;
 
1183
#ifdef HAVE_INT64_TIMESTAMP
 
1184
                                                                *fsec = rint(frac * 1000000);
 
1185
#else
 
1186
                                                                *fsec = frac;
 
1187
#endif
 
1188
                                                        }
 
1189
                                                        break;
 
1190
 
 
1191
                                                case DTK_TZ:
 
1192
                                                        tmask = DTK_M(TZ);
 
1193
                                                        dterr = DecodeTimezone(field[i], tzp);
 
1194
                                                        if (dterr)
 
1195
                                                                return dterr;
 
1196
                                                        break;
 
1197
 
 
1198
                                                case DTK_JULIAN:
 
1199
                                                        /***
 
1200
                                                         * previous field was a label for "julian date"?
 
1201
                                                         ***/
 
1202
                                                        tmask = DTK_DATE_M;
 
1203
                                                        j2date(val, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
 
1204
                                                        /* fractional Julian Day? */
 
1205
                                                        if (*cp == '.')
 
1206
                                                        {
 
1207
                                                                double          time;
 
1208
 
 
1209
                                                                time = strtod(cp, &cp);
 
1210
                                                                if (*cp != '\0')
 
1211
                                                                        return DTERR_BAD_FORMAT;
 
1212
 
 
1213
                                                                tmask |= DTK_TIME_M;
 
1214
#ifdef HAVE_INT64_TIMESTAMP
 
1215
                                                                dt2time((time * INT64CONST(86400000000)),
 
1216
                                                                                &tm->tm_hour, &tm->tm_min, &tm->tm_sec, fsec);
 
1217
#else
 
1218
                                                                dt2time((time * 86400),
 
1219
                                                                                &tm->tm_hour, &tm->tm_min, &tm->tm_sec, fsec);
 
1220
#endif
 
1221
                                                        }
 
1222
                                                        break;
 
1223
 
 
1224
                                                case DTK_TIME:
 
1225
                                                        /* previous field was "t" for ISO time */
 
1226
                                                        dterr = DecodeNumberField(strlen(field[i]), field[i],
 
1227
                                                                                                        (fmask | DTK_DATE_M),
 
1228
                                                                                                          &tmask, tm,
 
1229
                                                                                                          fsec, &is2digits);
 
1230
                                                        if (dterr < 0)
 
1231
                                                                return dterr;
 
1232
                                                        ftype[i] = dterr;
 
1233
 
 
1234
                                                        if (tmask != DTK_TIME_M)
 
1235
                                                                return DTERR_BAD_FORMAT;
 
1236
                                                        break;
 
1237
 
 
1238
                                                default:
 
1239
                                                        return DTERR_BAD_FORMAT;
 
1240
                                                        break;
 
1241
                                        }
 
1242
 
 
1243
                                        ptype = 0;
 
1244
                                        *dtype = DTK_DATE;
 
1245
                                }
 
1246
                                else
 
1247
                                {
 
1248
                                        char       *cp;
 
1249
                                        int                     flen;
 
1250
 
 
1251
                                        flen = strlen(field[i]);
 
1252
                                        cp = strchr(field[i], '.');
 
1253
 
 
1254
                                        /* Embedded decimal and no date yet? */
 
1255
                                        if ((cp != NULL) && !(fmask & DTK_DATE_M))
 
1256
                                        {
 
1257
                                                dterr = DecodeDate(field[i], fmask, &tmask, tm);
 
1258
                                                if (dterr)
 
1259
                                                        return dterr;
 
1260
                                        }
 
1261
                                        /* embedded decimal and several digits before? */
 
1262
                                        else if ((cp != NULL) && ((flen - strlen(cp)) > 2))
 
1263
                                        {
 
1264
                                                /*
 
1265
                                                 * Interpret as a concatenated date or time Set
 
1266
                                                 * the type field to allow decoding other fields
 
1267
                                                 * later. Example: 20011223 or 040506
 
1268
                                                 */
 
1269
                                                dterr = DecodeNumberField(flen, field[i], fmask,
 
1270
                                                                                                  &tmask, tm,
 
1271
                                                                                                  fsec, &is2digits);
 
1272
                                                if (dterr < 0)
 
1273
                                                        return dterr;
 
1274
                                                ftype[i] = dterr;
 
1275
                                        }
 
1276
                                        else if (flen > 4)
 
1277
                                        {
 
1278
                                                dterr = DecodeNumberField(flen, field[i], fmask,
 
1279
                                                                                                  &tmask, tm,
 
1280
                                                                                                  fsec, &is2digits);
 
1281
                                                if (dterr < 0)
 
1282
                                                        return dterr;
 
1283
                                                ftype[i] = dterr;
 
1284
                                        }
 
1285
                                        /* otherwise it is a single date/time field... */
 
1286
                                        else
 
1287
                                        {
 
1288
                                                dterr = DecodeNumber(flen, field[i],
 
1289
                                                                                         haveTextMonth, fmask,
 
1290
                                                                                         &tmask, tm,
 
1291
                                                                                         fsec, &is2digits);
 
1292
                                                if (dterr)
 
1293
                                                        return dterr;
 
1294
                                        }
 
1295
                                }
 
1296
                                break;
 
1297
 
 
1298
                        case DTK_STRING:
 
1299
                        case DTK_SPECIAL:
 
1300
                                type = DecodeSpecial(i, field[i], &val);
 
1301
                                if (type == IGNORE_DTF)
 
1302
                                        continue;
 
1303
 
 
1304
                                tmask = DTK_M(type);
 
1305
                                switch (type)
 
1306
                                {
 
1307
                                        case RESERV:
 
1308
                                                switch (val)
 
1309
                                                {
 
1310
                                                        case DTK_CURRENT:
 
1311
                                                                ereport(ERROR,
 
1312
                                                                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 
1313
                                                                  errmsg("date/time value \"current\" is no longer supported")));
 
1314
 
 
1315
                                                                return DTERR_BAD_FORMAT;
 
1316
                                                                break;
 
1317
 
 
1318
                                                        case DTK_NOW:
 
1319
                                                                tmask = (DTK_DATE_M | DTK_TIME_M | DTK_M(TZ));
 
1320
                                                                *dtype = DTK_DATE;
 
1321
                                                                GetCurrentTimeUsec(tm, fsec, tzp);
 
1322
                                                                break;
 
1323
 
 
1324
                                                        case DTK_YESTERDAY:
 
1325
                                                                tmask = DTK_DATE_M;
 
1326
                                                                *dtype = DTK_DATE;
 
1327
                                                                GetCurrentDateTime(tm);
 
1328
                                                                j2date((date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - 1),
 
1329
                                                                &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
 
1330
                                                                tm->tm_hour = 0;
 
1331
                                                                tm->tm_min = 0;
 
1332
                                                                tm->tm_sec = 0;
 
1333
                                                                break;
 
1334
 
 
1335
                                                        case DTK_TODAY:
 
1336
                                                                tmask = DTK_DATE_M;
 
1337
                                                                *dtype = DTK_DATE;
 
1338
                                                                GetCurrentDateTime(tm);
 
1339
                                                                tm->tm_hour = 0;
 
1340
                                                                tm->tm_min = 0;
 
1341
                                                                tm->tm_sec = 0;
 
1342
                                                                break;
 
1343
 
 
1344
                                                        case DTK_TOMORROW:
 
1345
                                                                tmask = DTK_DATE_M;
 
1346
                                                                *dtype = DTK_DATE;
 
1347
                                                                GetCurrentDateTime(tm);
 
1348
                                                                j2date((date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) + 1),
 
1349
                                                                &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
 
1350
                                                                tm->tm_hour = 0;
 
1351
                                                                tm->tm_min = 0;
 
1352
                                                                tm->tm_sec = 0;
 
1353
                                                                break;
 
1354
 
 
1355
                                                        case DTK_ZULU:
 
1356
                                                                tmask = (DTK_TIME_M | DTK_M(TZ));
 
1357
                                                                *dtype = DTK_DATE;
 
1358
                                                                tm->tm_hour = 0;
 
1359
                                                                tm->tm_min = 0;
 
1360
                                                                tm->tm_sec = 0;
 
1361
                                                                if (tzp != NULL)
 
1362
                                                                        *tzp = 0;
 
1363
                                                                break;
 
1364
 
 
1365
                                                        default:
 
1366
                                                                *dtype = val;
 
1367
                                                }
 
1368
 
 
1369
                                                break;
 
1370
 
 
1371
                                        case MONTH:
 
1372
 
 
1373
                                                /*
 
1374
                                                 * already have a (numeric) month? then see if we
 
1375
                                                 * can substitute...
 
1376
                                                 */
 
1377
                                                if ((fmask & DTK_M(MONTH)) && (!haveTextMonth)
 
1378
                                                        && (!(fmask & DTK_M(DAY)))
 
1379
                                                        && ((tm->tm_mon >= 1) && (tm->tm_mon <= 31)))
 
1380
                                                {
 
1381
                                                        tm->tm_mday = tm->tm_mon;
 
1382
                                                        tmask = DTK_M(DAY);
 
1383
                                                }
 
1384
                                                haveTextMonth = TRUE;
 
1385
                                                tm->tm_mon = val;
 
1386
                                                break;
 
1387
 
 
1388
                                        case DTZMOD:
 
1389
 
 
1390
                                                /*
 
1391
                                                 * daylight savings time modifier (solves "MET
 
1392
                                                 * DST" syntax)
 
1393
                                                 */
 
1394
                                                tmask |= DTK_M(DTZ);
 
1395
                                                tm->tm_isdst = 1;
 
1396
                                                if (tzp == NULL)
 
1397
                                                        return DTERR_BAD_FORMAT;
 
1398
                                                *tzp += val * 60;
 
1399
                                                break;
 
1400
 
 
1401
                                        case DTZ:
 
1402
 
 
1403
                                                /*
 
1404
                                                 * set mask for TZ here _or_ check for DTZ later
 
1405
                                                 * when getting default timezone
 
1406
                                                 */
 
1407
                                                tmask |= DTK_M(TZ);
 
1408
                                                tm->tm_isdst = 1;
 
1409
                                                if (tzp == NULL)
 
1410
                                                        return DTERR_BAD_FORMAT;
 
1411
                                                *tzp = val * 60;
 
1412
                                                ftype[i] = DTK_TZ;
 
1413
                                                break;
 
1414
 
 
1415
                                        case TZ:
 
1416
                                                tm->tm_isdst = 0;
 
1417
                                                if (tzp == NULL)
 
1418
                                                        return DTERR_BAD_FORMAT;
 
1419
                                                *tzp = val * 60;
 
1420
                                                ftype[i] = DTK_TZ;
 
1421
                                                break;
 
1422
 
 
1423
                                        case IGNORE_DTF:
 
1424
                                                break;
 
1425
 
 
1426
                                        case AMPM:
 
1427
                                                mer = val;
 
1428
                                                break;
 
1429
 
 
1430
                                        case ADBC:
 
1431
                                                bc = (val == BC);
 
1432
                                                break;
 
1433
 
 
1434
                                        case DOW:
 
1435
                                                tm->tm_wday = val;
 
1436
                                                break;
 
1437
 
 
1438
                                        case UNITS:
 
1439
                                                tmask = 0;
 
1440
                                                ptype = val;
 
1441
                                                break;
 
1442
 
 
1443
                                        case ISOTIME:
 
1444
 
 
1445
                                                /*
 
1446
                                                 * This is a filler field "t" indicating that the
 
1447
                                                 * next field is time. Try to verify that this is
 
1448
                                                 * sensible.
 
1449
                                                 */
 
1450
                                                tmask = 0;
 
1451
 
 
1452
                                                /* No preceding date? Then quit... */
 
1453
                                                if ((fmask & DTK_DATE_M) != DTK_DATE_M)
 
1454
                                                        return DTERR_BAD_FORMAT;
 
1455
 
 
1456
                                                /***
 
1457
                                                 * We will need one of the following fields:
 
1458
                                                 *      DTK_NUMBER should be hhmmss.fff
 
1459
                                                 *      DTK_TIME should be hh:mm:ss.fff
 
1460
                                                 *      DTK_DATE should be hhmmss-zz
 
1461
                                                 ***/
 
1462
                                                if ((i >= (nf - 1))
 
1463
                                                        || ((ftype[i + 1] != DTK_NUMBER)
 
1464
                                                                && (ftype[i + 1] != DTK_TIME)
 
1465
                                                                && (ftype[i + 1] != DTK_DATE)))
 
1466
                                                        return DTERR_BAD_FORMAT;
 
1467
 
 
1468
                                                ptype = val;
 
1469
                                                break;
 
1470
 
 
1471
                                        default:
 
1472
                                                return DTERR_BAD_FORMAT;
 
1473
                                }
 
1474
                                break;
 
1475
 
 
1476
                        default:
 
1477
                                return DTERR_BAD_FORMAT;
 
1478
                }
 
1479
 
 
1480
                if (tmask & fmask)
 
1481
                        return DTERR_BAD_FORMAT;
 
1482
                fmask |= tmask;
 
1483
        }
 
1484
 
 
1485
        if (fmask & DTK_M(YEAR))
 
1486
        {
 
1487
                /* there is no year zero in AD/BC notation; i.e. "1 BC" == year 0 */
 
1488
                if (bc)
 
1489
                {
 
1490
                        if (tm->tm_year > 0)
 
1491
                                tm->tm_year = -(tm->tm_year - 1);
 
1492
                        else
 
1493
                                ereport(ERROR,
 
1494
                                                (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
 
1495
                                           errmsg("inconsistent use of year %04d and \"BC\"",
 
1496
                                                          tm->tm_year)));
 
1497
                }
 
1498
                else if (is2digits)
 
1499
                {
 
1500
                        if (tm->tm_year < 70)
 
1501
                                tm->tm_year += 2000;
 
1502
                        else if (tm->tm_year < 100)
 
1503
                                tm->tm_year += 1900;
 
1504
                }
 
1505
        }
 
1506
 
 
1507
        /* now that we have correct year, decode DOY */
 
1508
        if (fmask & DTK_M(DOY))
 
1509
        {
 
1510
                j2date(date2j(tm->tm_year, 1, 1) + tm->tm_yday - 1,
 
1511
                           &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
 
1512
        }
 
1513
 
 
1514
        /* check for valid month */
 
1515
        if (fmask & DTK_M(MONTH))
 
1516
        {
 
1517
                if (tm->tm_mon < 1 || tm->tm_mon > 12)
 
1518
                        return DTERR_MD_FIELD_OVERFLOW;
 
1519
        }
 
1520
 
 
1521
        /* minimal check for valid day */
 
1522
        if (fmask & DTK_M(DAY))
 
1523
        {
 
1524
                if (tm->tm_mday < 1 || tm->tm_mday > 31)
 
1525
                        return DTERR_MD_FIELD_OVERFLOW;
 
1526
        }
 
1527
 
 
1528
        if ((mer != HR24) && (tm->tm_hour > 12))
 
1529
                return DTERR_FIELD_OVERFLOW;
 
1530
        if ((mer == AM) && (tm->tm_hour == 12))
 
1531
                tm->tm_hour = 0;
 
1532
        else if ((mer == PM) && (tm->tm_hour != 12))
 
1533
                tm->tm_hour += 12;
 
1534
 
 
1535
        /* do additional checking for full date specs... */
 
1536
        if (*dtype == DTK_DATE)
 
1537
        {
 
1538
                if ((fmask & DTK_DATE_M) != DTK_DATE_M)
 
1539
                {
 
1540
                        if ((fmask & DTK_TIME_M) == DTK_TIME_M)
 
1541
                                return 1;
 
1542
                        return DTERR_BAD_FORMAT;
 
1543
                }
 
1544
 
 
1545
                /*
 
1546
                 * Check for valid day of month, now that we know for sure the
 
1547
                 * month and year.      Note we don't use MD_FIELD_OVERFLOW here,
 
1548
                 * since it seems unlikely that "Feb 29" is a YMD-order error.
 
1549
                 */
 
1550
                if (tm->tm_mday > day_tab[isleap(tm->tm_year)][tm->tm_mon - 1])
 
1551
                        return DTERR_FIELD_OVERFLOW;
 
1552
 
 
1553
                /* timezone not specified? then find local timezone if possible */
 
1554
                if ((tzp != NULL) && (!(fmask & DTK_M(TZ))))
 
1555
                {
 
1556
                        /*
 
1557
                         * daylight savings time modifier but no standard timezone?
 
1558
                         * then error
 
1559
                         */
 
1560
                        if (fmask & DTK_M(DTZMOD))
 
1561
                                return DTERR_BAD_FORMAT;
 
1562
 
 
1563
                        *tzp = DetermineLocalTimeZone(tm);
 
1564
                }
 
1565
        }
 
1566
 
 
1567
        return 0;
 
1568
}
 
1569
 
 
1570
 
 
1571
/* DetermineLocalTimeZone()
 
1572
 *
 
1573
 * Given a struct pg_tm in which tm_year, tm_mon, tm_mday, tm_hour, tm_min, and
 
1574
 * tm_sec fields are set, attempt to determine the applicable local zone
 
1575
 * (ie, regular or daylight-savings time) at that time.  Set the struct pg_tm's
 
1576
 * tm_isdst field accordingly, and return the actual timezone offset.
 
1577
 *
 
1578
 * Note: it might seem that we should use mktime() for this, but bitter
 
1579
 * experience teaches otherwise.  This code is much faster than most versions
 
1580
 * of mktime(), anyway.
 
1581
 */
 
1582
int
 
1583
DetermineLocalTimeZone(struct pg_tm * tm)
 
1584
{
 
1585
        int                     date,
 
1586
                                sec;
 
1587
        pg_time_t       day,
 
1588
                                mytime,
 
1589
                                prevtime,
 
1590
                                boundary,
 
1591
                                beforetime,
 
1592
                                aftertime;
 
1593
        long int        before_gmtoff,
 
1594
                                after_gmtoff;
 
1595
        int                     before_isdst,
 
1596
                                after_isdst;
 
1597
        int                     res;
 
1598
 
 
1599
        if (HasCTZSet)
 
1600
        {
 
1601
                tm->tm_isdst = 0;               /* for lack of a better idea */
 
1602
                return CTimeZone;
 
1603
        }
 
1604
 
 
1605
        /*
 
1606
         * First, generate the pg_time_t value corresponding to the given
 
1607
         * y/m/d/h/m/s taken as GMT time.  If this overflows, punt and decide
 
1608
         * the timezone is GMT.  (We only need to worry about overflow on
 
1609
         * machines where pg_time_t is 32 bits.)
 
1610
         */
 
1611
        if (!IS_VALID_JULIAN(tm->tm_year, tm->tm_mon, tm->tm_mday))
 
1612
                goto overflow;
 
1613
        date = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - UNIX_EPOCH_JDATE;
 
1614
 
 
1615
        day = ((pg_time_t) date) *86400;
 
1616
        if (day / 86400 != date)
 
1617
                goto overflow;
 
1618
        sec = tm->tm_sec + (tm->tm_min + tm->tm_hour * 60) * 60;
 
1619
        mytime = day + sec;
 
1620
        /* since sec >= 0, overflow could only be from +day to -mytime */
 
1621
        if (mytime < 0 && day > 0)
 
1622
                goto overflow;
 
1623
 
 
1624
        /*
 
1625
         * Find the DST time boundary just before or following the target time.
 
1626
         * We assume that all zones have GMT offsets less than 24 hours, and
 
1627
         * that DST boundaries can't be closer together than 48 hours, so
 
1628
         * backing up 24 hours and finding the "next" boundary will work.
 
1629
         */
 
1630
        prevtime = mytime - (24 * 60 * 60);
 
1631
        if (mytime < 0 && prevtime > 0)
 
1632
                goto overflow;
 
1633
 
 
1634
        res = pg_next_dst_boundary(&prevtime,
 
1635
                                                           &before_gmtoff, &before_isdst,
 
1636
                                                           &boundary,
 
1637
                                                           &after_gmtoff, &after_isdst);
 
1638
        if (res < 0)
 
1639
                goto overflow;                  /* failure? */
 
1640
 
 
1641
        if (res == 0)
 
1642
        {
 
1643
                /* Non-DST zone, life is simple */
 
1644
                tm->tm_isdst = before_isdst;
 
1645
                return - (int) before_gmtoff;
 
1646
        }
 
1647
 
 
1648
        /*
 
1649
         * Form the candidate pg_time_t values with local-time adjustment
 
1650
         */
 
1651
        beforetime = mytime - before_gmtoff;
 
1652
        if ((before_gmtoff > 0) ? (mytime < 0 && beforetime > 0) :
 
1653
                (mytime > 0 && beforetime < 0))
 
1654
                goto overflow;
 
1655
        aftertime = mytime - after_gmtoff;
 
1656
        if ((after_gmtoff > 0) ? (mytime < 0 && aftertime > 0) :
 
1657
                (mytime > 0 && aftertime < 0))
 
1658
                goto overflow;
 
1659
 
 
1660
        /*
 
1661
         * If both before or both after the boundary time, we know what to do
 
1662
         */
 
1663
        if (beforetime <= boundary && aftertime < boundary)
 
1664
        {
 
1665
                tm->tm_isdst = before_isdst;
 
1666
                return - (int) before_gmtoff;
 
1667
        }
 
1668
        if (beforetime > boundary && aftertime >= boundary)
 
1669
        {
 
1670
                tm->tm_isdst = after_isdst;
 
1671
                return - (int) after_gmtoff;
 
1672
        }
 
1673
        /*
 
1674
         * It's an invalid or ambiguous time due to timezone transition.
 
1675
         * Prefer the standard-time interpretation.
 
1676
         */
 
1677
        if (after_isdst == 0)
 
1678
        {
 
1679
                tm->tm_isdst = after_isdst;
 
1680
                return - (int) after_gmtoff;
 
1681
        }
 
1682
        tm->tm_isdst = before_isdst;
 
1683
        return - (int) before_gmtoff;
 
1684
 
 
1685
overflow:
 
1686
        /* Given date is out of range, so assume UTC */
 
1687
        tm->tm_isdst = 0;
 
1688
        return 0;
 
1689
}
 
1690
 
 
1691
 
 
1692
/* DecodeTimeOnly()
 
1693
 * Interpret parsed string as time fields only.
 
1694
 * Returns 0 if successful, DTERR code if bogus input detected.
 
1695
 *
 
1696
 * Note that support for time zone is here for
 
1697
 * SQL92 TIME WITH TIME ZONE, but it reveals
 
1698
 * bogosity with SQL92 date/time standards, since
 
1699
 * we must infer a time zone from current time.
 
1700
 * - thomas 2000-03-10
 
1701
 * Allow specifying date to get a better time zone,
 
1702
 * if time zones are allowed. - thomas 2001-12-26
 
1703
 */
 
1704
int
 
1705
DecodeTimeOnly(char **field, int *ftype, int nf,
 
1706
                           int *dtype, struct pg_tm * tm, fsec_t *fsec, int *tzp)
 
1707
{
 
1708
        int                     fmask = 0,
 
1709
                                tmask,
 
1710
                                type;
 
1711
        int                     ptype = 0;              /* "prefix type" for ISO h04mm05s06 format */
 
1712
        int                     i;
 
1713
        int                     val;
 
1714
        int                     dterr;
 
1715
        int                     is2digits = FALSE;
 
1716
        int                     mer = HR24;
 
1717
 
 
1718
        *dtype = DTK_TIME;
 
1719
        tm->tm_hour = 0;
 
1720
        tm->tm_min = 0;
 
1721
        tm->tm_sec = 0;
 
1722
        *fsec = 0;
 
1723
        /* don't know daylight savings time status apriori */
 
1724
        tm->tm_isdst = -1;
 
1725
 
 
1726
        if (tzp != NULL)
 
1727
                *tzp = 0;
 
1728
 
 
1729
        for (i = 0; i < nf; i++)
 
1730
        {
 
1731
                switch (ftype[i])
 
1732
                {
 
1733
                        case DTK_DATE:
 
1734
 
 
1735
                                /*
 
1736
                                 * Time zone not allowed? Then should not accept dates or
 
1737
                                 * time zones no matter what else!
 
1738
                                 */
 
1739
                                if (tzp == NULL)
 
1740
                                        return DTERR_BAD_FORMAT;
 
1741
 
 
1742
                                /* Under limited circumstances, we will accept a date... */
 
1743
                                if ((i == 0) && (nf >= 2)
 
1744
                                        && ((ftype[nf - 1] == DTK_DATE)
 
1745
                                                || (ftype[1] == DTK_TIME)))
 
1746
                                {
 
1747
                                        dterr = DecodeDate(field[i], fmask, &tmask, tm);
 
1748
                                        if (dterr)
 
1749
                                                return dterr;
 
1750
                                }
 
1751
                                /* otherwise, this is a time and/or time zone */
 
1752
                                else
 
1753
                                {
 
1754
                                        if (isdigit((unsigned char) *field[i]))
 
1755
                                        {
 
1756
                                                char       *cp;
 
1757
 
 
1758
                                                /*
 
1759
                                                 * Starts with a digit but we already have a time
 
1760
                                                 * field? Then we are in trouble with time
 
1761
                                                 * already...
 
1762
                                                 */
 
1763
                                                if ((fmask & DTK_TIME_M) == DTK_TIME_M)
 
1764
                                                        return DTERR_BAD_FORMAT;
 
1765
 
 
1766
                                                /*
 
1767
                                                 * Should not get here and fail. Sanity check
 
1768
                                                 * only...
 
1769
                                                 */
 
1770
                                                if ((cp = strchr(field[i], '-')) == NULL)
 
1771
                                                        return DTERR_BAD_FORMAT;
 
1772
 
 
1773
                                                /* Get the time zone from the end of the string */
 
1774
                                                dterr = DecodeTimezone(cp, tzp);
 
1775
                                                if (dterr)
 
1776
                                                        return dterr;
 
1777
                                                *cp = '\0';
 
1778
 
 
1779
                                                /*
 
1780
                                                 * Then read the rest of the field as a
 
1781
                                                 * concatenated time
 
1782
                                                 */
 
1783
                                                dterr = DecodeNumberField(strlen(field[i]), field[i],
 
1784
                                                                                                  (fmask | DTK_DATE_M),
 
1785
                                                                                                  &tmask, tm,
 
1786
                                                                                                  fsec, &is2digits);
 
1787
                                                if (dterr < 0)
 
1788
                                                        return dterr;
 
1789
                                                ftype[i] = dterr;
 
1790
 
 
1791
                                                tmask |= DTK_M(TZ);
 
1792
                                        }
 
1793
                                        else
 
1794
                                        {
 
1795
                                                dterr = DecodePosixTimezone(field[i], tzp);
 
1796
                                                if (dterr)
 
1797
                                                        return dterr;
 
1798
 
 
1799
                                                ftype[i] = DTK_TZ;
 
1800
                                                tmask = DTK_M(TZ);
 
1801
                                        }
 
1802
                                }
 
1803
                                break;
 
1804
 
 
1805
                        case DTK_TIME:
 
1806
                                dterr = DecodeTime(field[i], (fmask | DTK_DATE_M),
 
1807
                                                                   &tmask, tm, fsec);
 
1808
                                if (dterr)
 
1809
                                        return dterr;
 
1810
                                break;
 
1811
 
 
1812
                        case DTK_TZ:
 
1813
                                {
 
1814
                                        int                     tz;
 
1815
 
 
1816
                                        if (tzp == NULL)
 
1817
                                                return DTERR_BAD_FORMAT;
 
1818
 
 
1819
                                        dterr = DecodeTimezone(field[i], &tz);
 
1820
                                        if (dterr)
 
1821
                                                return dterr;
 
1822
 
 
1823
                                        /*
 
1824
                                         * Already have a time zone? Then maybe this is the
 
1825
                                         * second field of a POSIX time: EST+3 (equivalent to
 
1826
                                         * PST)
 
1827
                                         */
 
1828
                                        if ((i > 0) && ((fmask & DTK_M(TZ)) != 0)
 
1829
                                                && (ftype[i - 1] == DTK_TZ) && (isalpha((unsigned char) *field[i - 1])))
 
1830
                                        {
 
1831
                                                *tzp -= tz;
 
1832
                                                tmask = 0;
 
1833
                                        }
 
1834
                                        else
 
1835
                                        {
 
1836
                                                *tzp = tz;
 
1837
                                                tmask = DTK_M(TZ);
 
1838
                                        }
 
1839
                                }
 
1840
                                break;
 
1841
 
 
1842
                        case DTK_NUMBER:
 
1843
 
 
1844
                                /*
 
1845
                                 * Was this an "ISO time" with embedded field labels? An
 
1846
                                 * example is "h04m05s06" - thomas 2001-02-04
 
1847
                                 */
 
1848
                                if (ptype != 0)
 
1849
                                {
 
1850
                                        char       *cp;
 
1851
                                        int                     val;
 
1852
 
 
1853
                                        /* Only accept a date under limited circumstances */
 
1854
                                        switch (ptype)
 
1855
                                        {
 
1856
                                                case DTK_JULIAN:
 
1857
                                                case DTK_YEAR:
 
1858
                                                case DTK_MONTH:
 
1859
                                                case DTK_DAY:
 
1860
                                                        if (tzp == NULL)
 
1861
                                                                return DTERR_BAD_FORMAT;
 
1862
                                                default:
 
1863
                                                        break;
 
1864
                                        }
 
1865
 
 
1866
                                        val = strtol(field[i], &cp, 10);
 
1867
 
 
1868
                                        /*
 
1869
                                         * only a few kinds are allowed to have an embedded
 
1870
                                         * decimal
 
1871
                                         */
 
1872
                                        if (*cp == '.')
 
1873
                                                switch (ptype)
 
1874
                                                {
 
1875
                                                        case DTK_JULIAN:
 
1876
                                                        case DTK_TIME:
 
1877
                                                        case DTK_SECOND:
 
1878
                                                                break;
 
1879
                                                        default:
 
1880
                                                                return DTERR_BAD_FORMAT;
 
1881
                                                                break;
 
1882
                                                }
 
1883
                                        else if (*cp != '\0')
 
1884
                                                return DTERR_BAD_FORMAT;
 
1885
 
 
1886
                                        switch (ptype)
 
1887
                                        {
 
1888
                                                case DTK_YEAR:
 
1889
                                                        tm->tm_year = val;
 
1890
                                                        tmask = DTK_M(YEAR);
 
1891
                                                        break;
 
1892
 
 
1893
                                                case DTK_MONTH:
 
1894
 
 
1895
                                                        /*
 
1896
                                                         * already have a month and hour? then assume
 
1897
                                                         * minutes
 
1898
                                                         */
 
1899
                                                        if (((fmask & DTK_M(MONTH)) != 0)
 
1900
                                                                && ((fmask & DTK_M(HOUR)) != 0))
 
1901
                                                        {
 
1902
                                                                tm->tm_min = val;
 
1903
                                                                tmask = DTK_M(MINUTE);
 
1904
                                                        }
 
1905
                                                        else
 
1906
                                                        {
 
1907
                                                                tm->tm_mon = val;
 
1908
                                                                tmask = DTK_M(MONTH);
 
1909
                                                        }
 
1910
                                                        break;
 
1911
 
 
1912
                                                case DTK_DAY:
 
1913
                                                        tm->tm_mday = val;
 
1914
                                                        tmask = DTK_M(DAY);
 
1915
                                                        break;
 
1916
 
 
1917
                                                case DTK_HOUR:
 
1918
                                                        tm->tm_hour = val;
 
1919
                                                        tmask = DTK_M(HOUR);
 
1920
                                                        break;
 
1921
 
 
1922
                                                case DTK_MINUTE:
 
1923
                                                        tm->tm_min = val;
 
1924
                                                        tmask = DTK_M(MINUTE);
 
1925
                                                        break;
 
1926
 
 
1927
                                                case DTK_SECOND:
 
1928
                                                        tm->tm_sec = val;
 
1929
                                                        tmask = DTK_M(SECOND);
 
1930
                                                        if (*cp == '.')
 
1931
                                                        {
 
1932
                                                                double          frac;
 
1933
 
 
1934
                                                                frac = strtod(cp, &cp);
 
1935
                                                                if (*cp != '\0')
 
1936
                                                                        return DTERR_BAD_FORMAT;
 
1937
#ifdef HAVE_INT64_TIMESTAMP
 
1938
                                                                *fsec = rint(frac * 1000000);
 
1939
#else
 
1940
                                                                *fsec = frac;
 
1941
#endif
 
1942
                                                        }
 
1943
                                                        break;
 
1944
 
 
1945
                                                case DTK_TZ:
 
1946
                                                        tmask = DTK_M(TZ);
 
1947
                                                        dterr = DecodeTimezone(field[i], tzp);
 
1948
                                                        if (dterr)
 
1949
                                                                return dterr;
 
1950
                                                        break;
 
1951
 
 
1952
                                                case DTK_JULIAN:
 
1953
                                                        /***
 
1954
                                                         * previous field was a label for "julian date"?
 
1955
                                                         ***/
 
1956
                                                        tmask = DTK_DATE_M;
 
1957
                                                        j2date(val, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
 
1958
                                                        if (*cp == '.')
 
1959
                                                        {
 
1960
                                                                double          time;
 
1961
 
 
1962
                                                                time = strtod(cp, &cp);
 
1963
                                                                if (*cp != '\0')
 
1964
                                                                        return DTERR_BAD_FORMAT;
 
1965
 
 
1966
                                                                tmask |= DTK_TIME_M;
 
1967
#ifdef HAVE_INT64_TIMESTAMP
 
1968
                                                                dt2time((time * INT64CONST(86400000000)),
 
1969
                                                                                &tm->tm_hour, &tm->tm_min, &tm->tm_sec, fsec);
 
1970
#else
 
1971
                                                                dt2time((time * 86400),
 
1972
                                                                                &tm->tm_hour, &tm->tm_min, &tm->tm_sec, fsec);
 
1973
#endif
 
1974
                                                        }
 
1975
                                                        break;
 
1976
 
 
1977
                                                case DTK_TIME:
 
1978
                                                        /* previous field was "t" for ISO time */
 
1979
                                                        dterr = DecodeNumberField(strlen(field[i]), field[i],
 
1980
                                                                                                        (fmask | DTK_DATE_M),
 
1981
                                                                                                          &tmask, tm,
 
1982
                                                                                                          fsec, &is2digits);
 
1983
                                                        if (dterr < 0)
 
1984
                                                                return dterr;
 
1985
                                                        ftype[i] = dterr;
 
1986
 
 
1987
                                                        if (tmask != DTK_TIME_M)
 
1988
                                                                return DTERR_BAD_FORMAT;
 
1989
                                                        break;
 
1990
 
 
1991
                                                default:
 
1992
                                                        return DTERR_BAD_FORMAT;
 
1993
                                                        break;
 
1994
                                        }
 
1995
 
 
1996
                                        ptype = 0;
 
1997
                                        *dtype = DTK_DATE;
 
1998
                                }
 
1999
                                else
 
2000
                                {
 
2001
                                        char       *cp;
 
2002
                                        int                     flen;
 
2003
 
 
2004
                                        flen = strlen(field[i]);
 
2005
                                        cp = strchr(field[i], '.');
 
2006
 
 
2007
                                        /* Embedded decimal? */
 
2008
                                        if (cp != NULL)
 
2009
                                        {
 
2010
                                                /*
 
2011
                                                 * Under limited circumstances, we will accept a
 
2012
                                                 * date...
 
2013
                                                 */
 
2014
                                                if ((i == 0) && ((nf >= 2) && (ftype[nf - 1] == DTK_DATE)))
 
2015
                                                {
 
2016
                                                        dterr = DecodeDate(field[i], fmask, &tmask, tm);
 
2017
                                                        if (dterr)
 
2018
                                                                return dterr;
 
2019
                                                }
 
2020
                                                /* embedded decimal and several digits before? */
 
2021
                                                else if ((flen - strlen(cp)) > 2)
 
2022
                                                {
 
2023
                                                        /*
 
2024
                                                         * Interpret as a concatenated date or time
 
2025
                                                         * Set the type field to allow decoding other
 
2026
                                                         * fields later. Example: 20011223 or 040506
 
2027
                                                         */
 
2028
                                                        dterr = DecodeNumberField(flen, field[i],
 
2029
                                                                                                        (fmask | DTK_DATE_M),
 
2030
                                                                                                          &tmask, tm,
 
2031
                                                                                                          fsec, &is2digits);
 
2032
                                                        if (dterr < 0)
 
2033
                                                                return dterr;
 
2034
                                                        ftype[i] = dterr;
 
2035
                                                }
 
2036
                                                else
 
2037
                                                        return DTERR_BAD_FORMAT;
 
2038
                                        }
 
2039
                                        else if (flen > 4)
 
2040
                                        {
 
2041
                                                dterr = DecodeNumberField(flen, field[i],
 
2042
                                                                                                  (fmask | DTK_DATE_M),
 
2043
                                                                                                  &tmask, tm,
 
2044
                                                                                                  fsec, &is2digits);
 
2045
                                                if (dterr < 0)
 
2046
                                                        return dterr;
 
2047
                                                ftype[i] = dterr;
 
2048
                                        }
 
2049
                                        /* otherwise it is a single date/time field... */
 
2050
                                        else
 
2051
                                        {
 
2052
                                                dterr = DecodeNumber(flen, field[i],
 
2053
                                                                                         FALSE,
 
2054
                                                                                         (fmask | DTK_DATE_M),
 
2055
                                                                                         &tmask, tm,
 
2056
                                                                                         fsec, &is2digits);
 
2057
                                                if (dterr)
 
2058
                                                        return dterr;
 
2059
                                        }
 
2060
                                }
 
2061
                                break;
 
2062
 
 
2063
                        case DTK_STRING:
 
2064
                        case DTK_SPECIAL:
 
2065
                                type = DecodeSpecial(i, field[i], &val);
 
2066
                                if (type == IGNORE_DTF)
 
2067
                                        continue;
 
2068
 
 
2069
                                tmask = DTK_M(type);
 
2070
                                switch (type)
 
2071
                                {
 
2072
                                        case RESERV:
 
2073
                                                switch (val)
 
2074
                                                {
 
2075
                                                        case DTK_CURRENT:
 
2076
                                                                ereport(ERROR,
 
2077
                                                                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 
2078
                                                                  errmsg("date/time value \"current\" is no longer supported")));
 
2079
                                                                return DTERR_BAD_FORMAT;
 
2080
                                                                break;
 
2081
 
 
2082
                                                        case DTK_NOW:
 
2083
                                                                tmask = DTK_TIME_M;
 
2084
                                                                *dtype = DTK_TIME;
 
2085
                                                                GetCurrentTimeUsec(tm, fsec, NULL);
 
2086
                                                                break;
 
2087
 
 
2088
                                                        case DTK_ZULU:
 
2089
                                                                tmask = (DTK_TIME_M | DTK_M(TZ));
 
2090
                                                                *dtype = DTK_TIME;
 
2091
                                                                tm->tm_hour = 0;
 
2092
                                                                tm->tm_min = 0;
 
2093
                                                                tm->tm_sec = 0;
 
2094
                                                                tm->tm_isdst = 0;
 
2095
                                                                break;
 
2096
 
 
2097
                                                        default:
 
2098
                                                                return DTERR_BAD_FORMAT;
 
2099
                                                }
 
2100
 
 
2101
                                                break;
 
2102
 
 
2103
                                        case DTZMOD:
 
2104
 
 
2105
                                                /*
 
2106
                                                 * daylight savings time modifier (solves "MET
 
2107
                                                 * DST" syntax)
 
2108
                                                 */
 
2109
                                                tmask |= DTK_M(DTZ);
 
2110
                                                tm->tm_isdst = 1;
 
2111
                                                if (tzp == NULL)
 
2112
                                                        return DTERR_BAD_FORMAT;
 
2113
                                                *tzp += val * 60;
 
2114
                                                break;
 
2115
 
 
2116
                                        case DTZ:
 
2117
 
 
2118
                                                /*
 
2119
                                                 * set mask for TZ here _or_ check for DTZ later
 
2120
                                                 * when getting default timezone
 
2121
                                                 */
 
2122
                                                tmask |= DTK_M(TZ);
 
2123
                                                tm->tm_isdst = 1;
 
2124
                                                if (tzp == NULL)
 
2125
                                                        return DTERR_BAD_FORMAT;
 
2126
                                                *tzp = val * 60;
 
2127
                                                ftype[i] = DTK_TZ;
 
2128
                                                break;
 
2129
 
 
2130
                                        case TZ:
 
2131
                                                tm->tm_isdst = 0;
 
2132
                                                if (tzp == NULL)
 
2133
                                                        return DTERR_BAD_FORMAT;
 
2134
                                                *tzp = val * 60;
 
2135
                                                ftype[i] = DTK_TZ;
 
2136
                                                break;
 
2137
 
 
2138
                                        case IGNORE_DTF:
 
2139
                                                break;
 
2140
 
 
2141
                                        case AMPM:
 
2142
                                                mer = val;
 
2143
                                                break;
 
2144
 
 
2145
                                        case UNITS:
 
2146
                                                tmask = 0;
 
2147
                                                ptype = val;
 
2148
                                                break;
 
2149
 
 
2150
                                        case ISOTIME:
 
2151
                                                tmask = 0;
 
2152
 
 
2153
                                                /***
 
2154
                                                 * We will need one of the following fields:
 
2155
                                                 *      DTK_NUMBER should be hhmmss.fff
 
2156
                                                 *      DTK_TIME should be hh:mm:ss.fff
 
2157
                                                 *      DTK_DATE should be hhmmss-zz
 
2158
                                                 ***/
 
2159
                                                if ((i >= (nf - 1))
 
2160
                                                        || ((ftype[i + 1] != DTK_NUMBER)
 
2161
                                                                && (ftype[i + 1] != DTK_TIME)
 
2162
                                                                && (ftype[i + 1] != DTK_DATE)))
 
2163
                                                        return DTERR_BAD_FORMAT;
 
2164
 
 
2165
                                                ptype = val;
 
2166
                                                break;
 
2167
 
 
2168
                                        default:
 
2169
                                                return DTERR_BAD_FORMAT;
 
2170
                                }
 
2171
                                break;
 
2172
 
 
2173
                        default:
 
2174
                                return DTERR_BAD_FORMAT;
 
2175
                }
 
2176
 
 
2177
                if (tmask & fmask)
 
2178
                        return DTERR_BAD_FORMAT;
 
2179
                fmask |= tmask;
 
2180
        }
 
2181
 
 
2182
        if ((mer != HR24) && (tm->tm_hour > 12))
 
2183
                return DTERR_FIELD_OVERFLOW;
 
2184
        if ((mer == AM) && (tm->tm_hour == 12))
 
2185
                tm->tm_hour = 0;
 
2186
        else if ((mer == PM) && (tm->tm_hour != 12))
 
2187
                tm->tm_hour += 12;
 
2188
 
 
2189
#ifdef HAVE_INT64_TIMESTAMP
 
2190
        if ((tm->tm_hour < 0) || (tm->tm_hour > 23)
 
2191
                || (tm->tm_min < 0) || (tm->tm_min > 59)
 
2192
                || (tm->tm_sec < 0) || (tm->tm_sec > 60)
 
2193
                || (*fsec < INT64CONST(0)) || (*fsec >= INT64CONST(1000000)))
 
2194
                return DTERR_FIELD_OVERFLOW;
 
2195
#else
 
2196
        if ((tm->tm_hour < 0) || (tm->tm_hour > 23)
 
2197
                || (tm->tm_min < 0) || (tm->tm_min > 59)
 
2198
                || (tm->tm_sec < 0) || (tm->tm_sec > 60)
 
2199
                || (*fsec < 0) || (*fsec >= 1))
 
2200
                return DTERR_FIELD_OVERFLOW;
 
2201
#endif
 
2202
 
 
2203
        if ((fmask & DTK_TIME_M) != DTK_TIME_M)
 
2204
                return DTERR_BAD_FORMAT;
 
2205
 
 
2206
        /* timezone not specified? then find local timezone if possible */
 
2207
        if ((tzp != NULL) && (!(fmask & DTK_M(TZ))))
 
2208
        {
 
2209
                struct pg_tm tt,
 
2210
                                   *tmp = &tt;
 
2211
 
 
2212
                /*
 
2213
                 * daylight savings time modifier but no standard timezone? then
 
2214
                 * error
 
2215
                 */
 
2216
                if (fmask & DTK_M(DTZMOD))
 
2217
                        return DTERR_BAD_FORMAT;
 
2218
 
 
2219
                if ((fmask & DTK_DATE_M) == 0)
 
2220
                        GetCurrentDateTime(tmp);
 
2221
                else
 
2222
                {
 
2223
                        tmp->tm_year = tm->tm_year;
 
2224
                        tmp->tm_mon = tm->tm_mon;
 
2225
                        tmp->tm_mday = tm->tm_mday;
 
2226
                }
 
2227
                tmp->tm_hour = tm->tm_hour;
 
2228
                tmp->tm_min = tm->tm_min;
 
2229
                tmp->tm_sec = tm->tm_sec;
 
2230
                *tzp = DetermineLocalTimeZone(tmp);
 
2231
                tm->tm_isdst = tmp->tm_isdst;
 
2232
        }
 
2233
 
 
2234
        return 0;
 
2235
}
 
2236
 
 
2237
/* DecodeDate()
 
2238
 * Decode date string which includes delimiters.
 
2239
 * Return 0 if okay, a DTERR code if not.
 
2240
 *
 
2241
 * Insist on a complete set of fields.
 
2242
 */
 
2243
static int
 
2244
DecodeDate(char *str, int fmask, int *tmask, struct pg_tm * tm)
 
2245
{
 
2246
        fsec_t          fsec;
 
2247
        int                     nf = 0;
 
2248
        int                     i,
 
2249
                                len;
 
2250
        int                     dterr;
 
2251
        bool            haveTextMonth = FALSE;
 
2252
        int                     bc = FALSE;
 
2253
        int                     is2digits = FALSE;
 
2254
        int                     type,
 
2255
                                val,
 
2256
                                dmask = 0;
 
2257
        char       *field[MAXDATEFIELDS];
 
2258
 
 
2259
        /* parse this string... */
 
2260
        while ((*str != '\0') && (nf < MAXDATEFIELDS))
 
2261
        {
 
2262
                /* skip field separators */
 
2263
                while (!isalnum((unsigned char) *str))
 
2264
                        str++;
 
2265
 
 
2266
                field[nf] = str;
 
2267
                if (isdigit((unsigned char) *str))
 
2268
                {
 
2269
                        while (isdigit((unsigned char) *str))
 
2270
                                str++;
 
2271
                }
 
2272
                else if (isalpha((unsigned char) *str))
 
2273
                {
 
2274
                        while (isalpha((unsigned char) *str))
 
2275
                                str++;
 
2276
                }
 
2277
 
 
2278
                /* Just get rid of any non-digit, non-alpha characters... */
 
2279
                if (*str != '\0')
 
2280
                        *str++ = '\0';
 
2281
                nf++;
 
2282
        }
 
2283
 
 
2284
#if 0
 
2285
        /* don't allow too many fields */
 
2286
        if (nf > 3)
 
2287
                return DTERR_BAD_FORMAT;
 
2288
#endif
 
2289
 
 
2290
        *tmask = 0;
 
2291
 
 
2292
        /* look first for text fields, since that will be unambiguous month */
 
2293
        for (i = 0; i < nf; i++)
 
2294
        {
 
2295
                if (isalpha((unsigned char) *field[i]))
 
2296
                {
 
2297
                        type = DecodeSpecial(i, field[i], &val);
 
2298
                        if (type == IGNORE_DTF)
 
2299
                                continue;
 
2300
 
 
2301
                        dmask = DTK_M(type);
 
2302
                        switch (type)
 
2303
                        {
 
2304
                                case MONTH:
 
2305
                                        tm->tm_mon = val;
 
2306
                                        haveTextMonth = TRUE;
 
2307
                                        break;
 
2308
 
 
2309
                                case ADBC:
 
2310
                                        bc = (val == BC);
 
2311
                                        break;
 
2312
 
 
2313
                                default:
 
2314
                                        return DTERR_BAD_FORMAT;
 
2315
                        }
 
2316
                        if (fmask & dmask)
 
2317
                                return DTERR_BAD_FORMAT;
 
2318
 
 
2319
                        fmask |= dmask;
 
2320
                        *tmask |= dmask;
 
2321
 
 
2322
                        /* mark this field as being completed */
 
2323
                        field[i] = NULL;
 
2324
                }
 
2325
        }
 
2326
 
 
2327
        /* now pick up remaining numeric fields */
 
2328
        for (i = 0; i < nf; i++)
 
2329
        {
 
2330
                if (field[i] == NULL)
 
2331
                        continue;
 
2332
 
 
2333
                if ((len = strlen(field[i])) <= 0)
 
2334
                        return DTERR_BAD_FORMAT;
 
2335
 
 
2336
                dterr = DecodeNumber(len, field[i], haveTextMonth, fmask,
 
2337
                                                         &dmask, tm,
 
2338
                                                         &fsec, &is2digits);
 
2339
                if (dterr)
 
2340
                        return dterr;
 
2341
 
 
2342
                if (fmask & dmask)
 
2343
                        return DTERR_BAD_FORMAT;
 
2344
 
 
2345
                fmask |= dmask;
 
2346
                *tmask |= dmask;
 
2347
        }
 
2348
 
 
2349
        if ((fmask & ~(DTK_M(DOY) | DTK_M(TZ))) != DTK_DATE_M)
 
2350
                return DTERR_BAD_FORMAT;
 
2351
 
 
2352
        /* there is no year zero in AD/BC notation; i.e. "1 BC" == year 0 */
 
2353
        if (bc)
 
2354
        {
 
2355
                if (tm->tm_year > 0)
 
2356
                        tm->tm_year = -(tm->tm_year - 1);
 
2357
                else
 
2358
                        ereport(ERROR,
 
2359
                                        (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
 
2360
                                         errmsg("inconsistent use of year %04d and \"BC\"",
 
2361
                                                        tm->tm_year)));
 
2362
        }
 
2363
        else if (is2digits)
 
2364
        {
 
2365
                if (tm->tm_year < 70)
 
2366
                        tm->tm_year += 2000;
 
2367
                else if (tm->tm_year < 100)
 
2368
                        tm->tm_year += 1900;
 
2369
        }
 
2370
 
 
2371
        /* now that we have correct year, decode DOY */
 
2372
        if (fmask & DTK_M(DOY))
 
2373
        {
 
2374
                j2date(date2j(tm->tm_year, 1, 1) + tm->tm_yday - 1,
 
2375
                           &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
 
2376
        }
 
2377
 
 
2378
        /* check for valid month */
 
2379
        if (tm->tm_mon < 1 || tm->tm_mon > 12)
 
2380
                return DTERR_MD_FIELD_OVERFLOW;
 
2381
 
 
2382
        /* check for valid day */
 
2383
        if (tm->tm_mday < 1 || tm->tm_mday > 31)
 
2384
                return DTERR_MD_FIELD_OVERFLOW;
 
2385
 
 
2386
        /* We don't want to hint about DateStyle for Feb 29 */
 
2387
        if (tm->tm_mday > day_tab[isleap(tm->tm_year)][tm->tm_mon - 1])
 
2388
                return DTERR_FIELD_OVERFLOW;
 
2389
 
 
2390
        return 0;
 
2391
}
 
2392
 
 
2393
 
 
2394
/* DecodeTime()
 
2395
 * Decode time string which includes delimiters.
 
2396
 * Return 0 if okay, a DTERR code if not.
 
2397
 *
 
2398
 * Only check the lower limit on hours, since this same code
 
2399
 *      can be used to represent time spans.
 
2400
 */
 
2401
static int
 
2402
DecodeTime(char *str, int fmask, int *tmask, struct pg_tm * tm, fsec_t *fsec)
 
2403
{
 
2404
        char       *cp;
 
2405
 
 
2406
        *tmask = DTK_TIME_M;
 
2407
 
 
2408
        tm->tm_hour = strtol(str, &cp, 10);
 
2409
        if (*cp != ':')
 
2410
                return DTERR_BAD_FORMAT;
 
2411
        str = cp + 1;
 
2412
        tm->tm_min = strtol(str, &cp, 10);
 
2413
        if (*cp == '\0')
 
2414
        {
 
2415
                tm->tm_sec = 0;
 
2416
                *fsec = 0;
 
2417
        }
 
2418
        else if (*cp != ':')
 
2419
                return DTERR_BAD_FORMAT;
 
2420
        else
 
2421
        {
 
2422
                str = cp + 1;
 
2423
                tm->tm_sec = strtol(str, &cp, 10);
 
2424
                if (*cp == '\0')
 
2425
                        *fsec = 0;
 
2426
                else if (*cp == '.')
 
2427
                {
 
2428
                        double          frac;
 
2429
 
 
2430
                        str = cp;
 
2431
                        frac = strtod(str, &cp);
 
2432
                        if (*cp != '\0')
 
2433
                                return DTERR_BAD_FORMAT;
 
2434
#ifdef HAVE_INT64_TIMESTAMP
 
2435
                        *fsec = rint(frac * 1000000);
 
2436
#else
 
2437
                        *fsec = frac;
 
2438
#endif
 
2439
                }
 
2440
                else
 
2441
                        return DTERR_BAD_FORMAT;
 
2442
        }
 
2443
 
 
2444
        /* do a sanity check */
 
2445
#ifdef HAVE_INT64_TIMESTAMP
 
2446
        if ((tm->tm_hour < 0)
 
2447
                || (tm->tm_min < 0) || (tm->tm_min > 59)
 
2448
                || (tm->tm_sec < 0) || (tm->tm_sec > 60)
 
2449
                || (*fsec < INT64CONST(0)) || (*fsec >= INT64CONST(1000000)))
 
2450
                return DTERR_FIELD_OVERFLOW;
 
2451
#else
 
2452
        if ((tm->tm_hour < 0)
 
2453
                || (tm->tm_min < 0) || (tm->tm_min > 59)
 
2454
                || (tm->tm_sec < 0) || (tm->tm_sec > 60)
 
2455
                || (*fsec < 0) || (*fsec >= 1))
 
2456
                return DTERR_FIELD_OVERFLOW;
 
2457
#endif
 
2458
 
 
2459
        return 0;
 
2460
}
 
2461
 
 
2462
 
 
2463
/* DecodeNumber()
 
2464
 * Interpret plain numeric field as a date value in context.
 
2465
 * Return 0 if okay, a DTERR code if not.
 
2466
 */
 
2467
static int
 
2468
DecodeNumber(int flen, char *str, bool haveTextMonth, int fmask,
 
2469
                         int *tmask, struct pg_tm * tm, fsec_t *fsec, int *is2digits)
 
2470
{
 
2471
        int                     val;
 
2472
        char       *cp;
 
2473
        int                     dterr;
 
2474
 
 
2475
        *tmask = 0;
 
2476
 
 
2477
        val = strtol(str, &cp, 10);
 
2478
        if (cp == str)
 
2479
                return DTERR_BAD_FORMAT;
 
2480
 
 
2481
        if (*cp == '.')
 
2482
        {
 
2483
                double          frac;
 
2484
 
 
2485
                /*
 
2486
                 * More than two digits before decimal point? Then could be a date
 
2487
                 * or a run-together time: 2001.360 20011225 040506.789
 
2488
                 */
 
2489
                if ((cp - str) > 2)
 
2490
                {
 
2491
                        dterr = DecodeNumberField(flen, str,
 
2492
                                                                          (fmask | DTK_DATE_M),
 
2493
                                                                          tmask, tm,
 
2494
                                                                          fsec, is2digits);
 
2495
                        if (dterr < 0)
 
2496
                                return dterr;
 
2497
                        return 0;
 
2498
                }
 
2499
 
 
2500
                frac = strtod(cp, &cp);
 
2501
                if (*cp != '\0')
 
2502
                        return DTERR_BAD_FORMAT;
 
2503
#ifdef HAVE_INT64_TIMESTAMP
 
2504
                *fsec = rint(frac * 1000000);
 
2505
#else
 
2506
                *fsec = frac;
 
2507
#endif
 
2508
        }
 
2509
        else if (*cp != '\0')
 
2510
                return DTERR_BAD_FORMAT;
 
2511
 
 
2512
        /* Special case for day of year */
 
2513
        if ((flen == 3) &&
 
2514
                ((fmask & DTK_DATE_M) == DTK_M(YEAR)) &&
 
2515
                ((val >= 1) && (val <= 366)))
 
2516
        {
 
2517
                *tmask = (DTK_M(DOY) | DTK_M(MONTH) | DTK_M(DAY));
 
2518
                tm->tm_yday = val;
 
2519
                /* tm_mon and tm_mday can't actually be set yet ... */
 
2520
                return 0;
 
2521
        }
 
2522
 
 
2523
        /* Switch based on what we have so far */
 
2524
        switch (fmask & DTK_DATE_M)
 
2525
        {
 
2526
                case 0:
 
2527
 
 
2528
                        /*
 
2529
                         * Nothing so far; make a decision about what we think the
 
2530
                         * input is.  There used to be lots of heuristics here, but
 
2531
                         * the consensus now is to be paranoid.  It *must* be either
 
2532
                         * YYYY-MM-DD (with a more-than-two-digit year field), or the
 
2533
                         * field order defined by DateOrder.
 
2534
                         */
 
2535
                        if (flen >= 3 || DateOrder == DATEORDER_YMD)
 
2536
                        {
 
2537
                                *tmask = DTK_M(YEAR);
 
2538
                                tm->tm_year = val;
 
2539
                        }
 
2540
                        else if (DateOrder == DATEORDER_DMY)
 
2541
                        {
 
2542
                                *tmask = DTK_M(DAY);
 
2543
                                tm->tm_mday = val;
 
2544
                        }
 
2545
                        else
 
2546
                        {
 
2547
                                *tmask = DTK_M(MONTH);
 
2548
                                tm->tm_mon = val;
 
2549
                        }
 
2550
                        break;
 
2551
 
 
2552
                case (DTK_M(YEAR)):
 
2553
                        /* Must be at second field of YY-MM-DD */
 
2554
                        *tmask = DTK_M(MONTH);
 
2555
                        tm->tm_mon = val;
 
2556
                        break;
 
2557
 
 
2558
                case (DTK_M(MONTH)):
 
2559
                        if (haveTextMonth)
 
2560
                        {
 
2561
                                /*
 
2562
                                 * We are at the first numeric field of a date that
 
2563
                                 * included a textual month name.  We want to support the
 
2564
                                 * variants MON-DD-YYYY, DD-MON-YYYY, and YYYY-MON-DD as
 
2565
                                 * unambiguous inputs.  We will also accept MON-DD-YY or
 
2566
                                 * DD-MON-YY in either DMY or MDY modes, as well as
 
2567
                                 * YY-MON-DD in YMD mode.
 
2568
                                 */
 
2569
                                if (flen >= 3 || DateOrder == DATEORDER_YMD)
 
2570
                                {
 
2571
                                        *tmask = DTK_M(YEAR);
 
2572
                                        tm->tm_year = val;
 
2573
                                }
 
2574
                                else
 
2575
                                {
 
2576
                                        *tmask = DTK_M(DAY);
 
2577
                                        tm->tm_mday = val;
 
2578
                                }
 
2579
                        }
 
2580
                        else
 
2581
                        {
 
2582
                                /* Must be at second field of MM-DD-YY */
 
2583
                                *tmask = DTK_M(DAY);
 
2584
                                tm->tm_mday = val;
 
2585
                        }
 
2586
                        break;
 
2587
 
 
2588
                case (DTK_M(YEAR) | DTK_M(MONTH)):
 
2589
                        if (haveTextMonth)
 
2590
                        {
 
2591
                                /* Need to accept DD-MON-YYYY even in YMD mode */
 
2592
                                if (flen >= 3 && *is2digits)
 
2593
                                {
 
2594
                                        /* Guess that first numeric field is day was wrong */
 
2595
                                        *tmask = DTK_M(DAY);            /* YEAR is already set */
 
2596
                                        tm->tm_mday = tm->tm_year;
 
2597
                                        tm->tm_year = val;
 
2598
                                        *is2digits = FALSE;
 
2599
                                }
 
2600
                                else
 
2601
                                {
 
2602
                                        *tmask = DTK_M(DAY);
 
2603
                                        tm->tm_mday = val;
 
2604
                                }
 
2605
                        }
 
2606
                        else
 
2607
                        {
 
2608
                                /* Must be at third field of YY-MM-DD */
 
2609
                                *tmask = DTK_M(DAY);
 
2610
                                tm->tm_mday = val;
 
2611
                        }
 
2612
                        break;
 
2613
 
 
2614
                case (DTK_M(DAY)):
 
2615
                        /* Must be at second field of DD-MM-YY */
 
2616
                        *tmask = DTK_M(MONTH);
 
2617
                        tm->tm_mon = val;
 
2618
                        break;
 
2619
 
 
2620
                case (DTK_M(MONTH) | DTK_M(DAY)):
 
2621
                        /* Must be at third field of DD-MM-YY or MM-DD-YY */
 
2622
                        *tmask = DTK_M(YEAR);
 
2623
                        tm->tm_year = val;
 
2624
                        break;
 
2625
 
 
2626
                case (DTK_M(YEAR) | DTK_M(MONTH) | DTK_M(DAY)):
 
2627
                        /* we have all the date, so it must be a time field */
 
2628
                        dterr = DecodeNumberField(flen, str, fmask,
 
2629
                                                                          tmask, tm,
 
2630
                                                                          fsec, is2digits);
 
2631
                        if (dterr < 0)
 
2632
                                return dterr;
 
2633
                        return 0;
 
2634
 
 
2635
                default:
 
2636
                        /* Anything else is bogus input */
 
2637
                        return DTERR_BAD_FORMAT;
 
2638
        }
 
2639
 
 
2640
        /*
 
2641
         * When processing a year field, mark it for adjustment if it's only
 
2642
         * one or two digits.
 
2643
         */
 
2644
        if (*tmask == DTK_M(YEAR))
 
2645
                *is2digits = (flen <= 2);
 
2646
 
 
2647
        return 0;
 
2648
}
 
2649
 
 
2650
 
 
2651
/* DecodeNumberField()
 
2652
 * Interpret numeric string as a concatenated date or time field.
 
2653
 * Return a DTK token (>= 0) if successful, a DTERR code (< 0) if not.
 
2654
 *
 
2655
 * Use the context of previously decoded fields to help with
 
2656
 * the interpretation.
 
2657
 */
 
2658
static int
 
2659
DecodeNumberField(int len, char *str, int fmask,
 
2660
                         int *tmask, struct pg_tm * tm, fsec_t *fsec, int *is2digits)
 
2661
{
 
2662
        char       *cp;
 
2663
 
 
2664
        /*
 
2665
         * Have a decimal point? Then this is a date or something with a
 
2666
         * seconds field...
 
2667
         */
 
2668
        if ((cp = strchr(str, '.')) != NULL)
 
2669
        {
 
2670
                double          frac;
 
2671
 
 
2672
                frac = strtod(cp, NULL);
 
2673
#ifdef HAVE_INT64_TIMESTAMP
 
2674
                *fsec = rint(frac * 1000000);
 
2675
#else
 
2676
                *fsec = frac;
 
2677
#endif
 
2678
                *cp = '\0';
 
2679
                len = strlen(str);
 
2680
        }
 
2681
        /* No decimal point and no complete date yet? */
 
2682
        else if ((fmask & DTK_DATE_M) != DTK_DATE_M)
 
2683
        {
 
2684
                /* yyyymmdd? */
 
2685
                if (len == 8)
 
2686
                {
 
2687
                        *tmask = DTK_DATE_M;
 
2688
 
 
2689
                        tm->tm_mday = atoi(str + 6);
 
2690
                        *(str + 6) = '\0';
 
2691
                        tm->tm_mon = atoi(str + 4);
 
2692
                        *(str + 4) = '\0';
 
2693
                        tm->tm_year = atoi(str + 0);
 
2694
 
 
2695
                        return DTK_DATE;
 
2696
                }
 
2697
                /* yymmdd? */
 
2698
                else if (len == 6)
 
2699
                {
 
2700
                        *tmask = DTK_DATE_M;
 
2701
                        tm->tm_mday = atoi(str + 4);
 
2702
                        *(str + 4) = '\0';
 
2703
                        tm->tm_mon = atoi(str + 2);
 
2704
                        *(str + 2) = '\0';
 
2705
                        tm->tm_year = atoi(str + 0);
 
2706
                        *is2digits = TRUE;
 
2707
 
 
2708
                        return DTK_DATE;
 
2709
                }
 
2710
        }
 
2711
 
 
2712
        /* not all time fields are specified? */
 
2713
        if ((fmask & DTK_TIME_M) != DTK_TIME_M)
 
2714
        {
 
2715
                /* hhmmss */
 
2716
                if (len == 6)
 
2717
                {
 
2718
                        *tmask = DTK_TIME_M;
 
2719
                        tm->tm_sec = atoi(str + 4);
 
2720
                        *(str + 4) = '\0';
 
2721
                        tm->tm_min = atoi(str + 2);
 
2722
                        *(str + 2) = '\0';
 
2723
                        tm->tm_hour = atoi(str + 0);
 
2724
 
 
2725
                        return DTK_TIME;
 
2726
                }
 
2727
                /* hhmm? */
 
2728
                else if (len == 4)
 
2729
                {
 
2730
                        *tmask = DTK_TIME_M;
 
2731
                        tm->tm_sec = 0;
 
2732
                        tm->tm_min = atoi(str + 2);
 
2733
                        *(str + 2) = '\0';
 
2734
                        tm->tm_hour = atoi(str + 0);
 
2735
 
 
2736
                        return DTK_TIME;
 
2737
                }
 
2738
        }
 
2739
 
 
2740
        return DTERR_BAD_FORMAT;
 
2741
}
 
2742
 
 
2743
 
 
2744
/* DecodeTimezone()
 
2745
 * Interpret string as a numeric timezone.
 
2746
 *
 
2747
 * Return 0 if okay (and set *tzp), a DTERR code if not okay.
 
2748
 *
 
2749
 * NB: this must *not* ereport on failure; see commands/variable.c.
 
2750
 *
 
2751
 * Note: we allow timezone offsets up to 13:59.  There are places that
 
2752
 * use +1300 summer time.
 
2753
 */
 
2754
static int
 
2755
DecodeTimezone(char *str, int *tzp)
 
2756
{
 
2757
        int                     tz;
 
2758
        int                     hr,
 
2759
                                min;
 
2760
        char       *cp;
 
2761
 
 
2762
        /* leading character must be "+" or "-" */
 
2763
        if (*str != '+' && *str != '-')
 
2764
                return DTERR_BAD_FORMAT;
 
2765
 
 
2766
        hr = strtol((str + 1), &cp, 10);
 
2767
 
 
2768
        /* explicit delimiter? */
 
2769
        if (*cp == ':')
 
2770
                min = strtol((cp + 1), &cp, 10);
 
2771
        /* otherwise, might have run things together... */
 
2772
        else if ((*cp == '\0') && (strlen(str) > 3))
 
2773
        {
 
2774
                min = hr % 100;
 
2775
                hr = hr / 100;
 
2776
        }
 
2777
        else
 
2778
                min = 0;
 
2779
 
 
2780
        if ((hr < 0) || (hr > 13))
 
2781
                return DTERR_TZDISP_OVERFLOW;
 
2782
        if ((min < 0) || (min >= 60))
 
2783
                return DTERR_TZDISP_OVERFLOW;
 
2784
 
 
2785
        tz = (hr * 60 + min) * 60;
 
2786
        if (*str == '-')
 
2787
                tz = -tz;
 
2788
 
 
2789
        *tzp = -tz;
 
2790
 
 
2791
        if (*cp != '\0')
 
2792
                return DTERR_BAD_FORMAT;
 
2793
 
 
2794
        return 0;
 
2795
}
 
2796
 
 
2797
 
 
2798
/* DecodePosixTimezone()
 
2799
 * Interpret string as a POSIX-compatible timezone:
 
2800
 *      PST-hh:mm
 
2801
 *      PST+h
 
2802
 *      PST
 
2803
 * - thomas 2000-03-15
 
2804
 *
 
2805
 * Return 0 if okay (and set *tzp), a DTERR code if not okay.
 
2806
 */
 
2807
static int
 
2808
DecodePosixTimezone(char *str, int *tzp)
 
2809
{
 
2810
        int                     val,
 
2811
                                tz;
 
2812
        int                     type;
 
2813
        int                     dterr;
 
2814
        char       *cp;
 
2815
        char            delim;
 
2816
 
 
2817
        /* advance over name part */
 
2818
        cp = str;
 
2819
        while (*cp && isalpha((unsigned char) *cp))
 
2820
                cp++;
 
2821
 
 
2822
        /* decode offset, if present */
 
2823
        if (*cp)
 
2824
        {
 
2825
                dterr = DecodeTimezone(cp, &tz);
 
2826
                if (dterr)
 
2827
                        return dterr;
 
2828
        }
 
2829
        else
 
2830
                tz = 0;
 
2831
 
 
2832
        /* decode name part.  We must temporarily scribble on the input! */
 
2833
        delim = *cp;
 
2834
        *cp = '\0';
 
2835
        type = DecodeSpecial(MAXDATEFIELDS - 1, str, &val);
 
2836
        *cp = delim;
 
2837
 
 
2838
        switch (type)
 
2839
        {
 
2840
                case DTZ:
 
2841
                case TZ:
 
2842
                        *tzp = (val * 60) - tz;
 
2843
                        break;
 
2844
 
 
2845
                default:
 
2846
                        return DTERR_BAD_FORMAT;
 
2847
        }
 
2848
 
 
2849
        return 0;
 
2850
}
 
2851
 
 
2852
 
 
2853
/* DecodeSpecial()
 
2854
 * Decode text string using lookup table.
 
2855
 *
 
2856
 * Implement a cache lookup since it is likely that dates
 
2857
 *      will be related in format.
 
2858
 *
 
2859
 * NB: this must *not* ereport on failure;
 
2860
 * see commands/variable.c.
 
2861
 */
 
2862
int
 
2863
DecodeSpecial(int field, char *lowtoken, int *val)
 
2864
{
 
2865
        int                     type;
 
2866
        datetkn    *tp;
 
2867
 
 
2868
        if ((datecache[field] != NULL)
 
2869
                && (strncmp(lowtoken, datecache[field]->token, TOKMAXLEN) == 0))
 
2870
                tp = datecache[field];
 
2871
        else
 
2872
        {
 
2873
                tp = NULL;
 
2874
                if (Australian_timezones)
 
2875
                        tp = datebsearch(lowtoken, australian_datetktbl,
 
2876
                                                         australian_szdatetktbl);
 
2877
                if (!tp)
 
2878
                        tp = datebsearch(lowtoken, datetktbl, szdatetktbl);
 
2879
        }
 
2880
        datecache[field] = tp;
 
2881
        if (tp == NULL)
 
2882
        {
 
2883
                type = UNKNOWN_FIELD;
 
2884
                *val = 0;
 
2885
        }
 
2886
        else
 
2887
        {
 
2888
                type = tp->type;
 
2889
                switch (type)
 
2890
                {
 
2891
                        case TZ:
 
2892
                        case DTZ:
 
2893
                        case DTZMOD:
 
2894
                                *val = FROMVAL(tp);
 
2895
                                break;
 
2896
 
 
2897
                        default:
 
2898
                                *val = tp->value;
 
2899
                                break;
 
2900
                }
 
2901
        }
 
2902
 
 
2903
        return type;
 
2904
}
 
2905
 
 
2906
 
 
2907
/* DecodeInterval()
 
2908
 * Interpret previously parsed fields for general time interval.
 
2909
 * Returns 0 if successful, DTERR code if bogus input detected.
 
2910
 *
 
2911
 * Allow "date" field DTK_DATE since this could be just
 
2912
 *      an unsigned floating point number. - thomas 1997-11-16
 
2913
 *
 
2914
 * Allow ISO-style time span, with implicit units on number of days
 
2915
 *      preceding an hh:mm:ss field. - thomas 1998-04-30
 
2916
 */
 
2917
int
 
2918
DecodeInterval(char **field, int *ftype, int nf, int *dtype, struct pg_tm * tm, fsec_t *fsec)
 
2919
{
 
2920
        int                     is_before = FALSE;
 
2921
        char       *cp;
 
2922
        int                     fmask = 0,
 
2923
                                tmask,
 
2924
                                type;
 
2925
        int                     i;
 
2926
        int                     dterr;
 
2927
        int                     val;
 
2928
        double          fval;
 
2929
 
 
2930
        *dtype = DTK_DELTA;
 
2931
 
 
2932
        type = IGNORE_DTF;
 
2933
        tm->tm_year = 0;
 
2934
        tm->tm_mon = 0;
 
2935
        tm->tm_mday = 0;
 
2936
        tm->tm_hour = 0;
 
2937
        tm->tm_min = 0;
 
2938
        tm->tm_sec = 0;
 
2939
        *fsec = 0;
 
2940
 
 
2941
        /* read through list backwards to pick up units before values */
 
2942
        for (i = nf - 1; i >= 0; i--)
 
2943
        {
 
2944
                switch (ftype[i])
 
2945
                {
 
2946
                        case DTK_TIME:
 
2947
                                dterr = DecodeTime(field[i], fmask, &tmask, tm, fsec);
 
2948
                                if (dterr)
 
2949
                                        return dterr;
 
2950
                                type = DTK_DAY;
 
2951
                                break;
 
2952
 
 
2953
                        case DTK_TZ:
 
2954
 
 
2955
                                /*
 
2956
                                 * Timezone is a token with a leading sign character and
 
2957
                                 * otherwise the same as a non-signed time field
 
2958
                                 */
 
2959
                                Assert((*field[i] == '-') || (*field[i] == '+'));
 
2960
 
 
2961
                                /*
 
2962
                                 * A single signed number ends up here, but will be
 
2963
                                 * rejected by DecodeTime(). So, work this out to drop
 
2964
                                 * through to DTK_NUMBER, which *can* tolerate this.
 
2965
                                 */
 
2966
                                cp = field[i] + 1;
 
2967
                                while ((*cp != '\0') && (*cp != ':') && (*cp != '.'))
 
2968
                                        cp++;
 
2969
                                if ((*cp == ':') &&
 
2970
                                (DecodeTime(field[i] + 1, fmask, &tmask, tm, fsec) == 0))
 
2971
                                {
 
2972
                                        if (*field[i] == '-')
 
2973
                                        {
 
2974
                                                /* flip the sign on all fields */
 
2975
                                                tm->tm_hour = -tm->tm_hour;
 
2976
                                                tm->tm_min = -tm->tm_min;
 
2977
                                                tm->tm_sec = -tm->tm_sec;
 
2978
                                                *fsec = -(*fsec);
 
2979
                                        }
 
2980
 
 
2981
                                        /*
 
2982
                                         * Set the next type to be a day, if units are not
 
2983
                                         * specified. This handles the case of '1 +02:03'
 
2984
                                         * since we are reading right to left.
 
2985
                                         */
 
2986
                                        type = DTK_DAY;
 
2987
                                        tmask = DTK_M(TZ);
 
2988
                                        break;
 
2989
                                }
 
2990
                                else if (type == IGNORE_DTF)
 
2991
                                {
 
2992
                                        if (*cp == '.')
 
2993
                                        {
 
2994
                                                /*
 
2995
                                                 * Got a decimal point? Then assume some sort of
 
2996
                                                 * seconds specification
 
2997
                                                 */
 
2998
                                                type = DTK_SECOND;
 
2999
                                        }
 
3000
                                        else if (*cp == '\0')
 
3001
                                        {
 
3002
                                                /*
 
3003
                                                 * Only a signed integer? Then must assume a
 
3004
                                                 * timezone-like usage
 
3005
                                                 */
 
3006
                                                type = DTK_HOUR;
 
3007
                                        }
 
3008
                                }
 
3009
                                /* DROP THROUGH */
 
3010
 
 
3011
                        case DTK_DATE:
 
3012
                        case DTK_NUMBER:
 
3013
                                val = strtol(field[i], &cp, 10);
 
3014
 
 
3015
                                if (type == IGNORE_DTF)
 
3016
                                        type = DTK_SECOND;
 
3017
 
 
3018
                                if (*cp == '.')
 
3019
                                {
 
3020
                                        fval = strtod(cp, &cp);
 
3021
                                        if (*cp != '\0')
 
3022
                                                return DTERR_BAD_FORMAT;
 
3023
 
 
3024
                                        if (*field[i] == '-')
 
3025
                                                fval = -(fval);
 
3026
                                }
 
3027
                                else if (*cp == '\0')
 
3028
                                        fval = 0;
 
3029
                                else
 
3030
                                        return DTERR_BAD_FORMAT;
 
3031
 
 
3032
                                tmask = 0;              /* DTK_M(type); */
 
3033
 
 
3034
                                switch (type)
 
3035
                                {
 
3036
                                        case DTK_MICROSEC:
 
3037
#ifdef HAVE_INT64_TIMESTAMP
 
3038
                                                *fsec += (val + fval);
 
3039
#else
 
3040
                                                *fsec += ((val + fval) * 1e-6);
 
3041
#endif
 
3042
                                                break;
 
3043
 
 
3044
                                        case DTK_MILLISEC:
 
3045
#ifdef HAVE_INT64_TIMESTAMP
 
3046
                                                *fsec += ((val + fval) * 1000);
 
3047
#else
 
3048
                                                *fsec += ((val + fval) * 1e-3);
 
3049
#endif
 
3050
                                                break;
 
3051
 
 
3052
                                        case DTK_SECOND:
 
3053
                                                tm->tm_sec += val;
 
3054
#ifdef HAVE_INT64_TIMESTAMP
 
3055
                                                *fsec += (fval * 1000000);
 
3056
#else
 
3057
                                                *fsec += fval;
 
3058
#endif
 
3059
                                                tmask = DTK_M(SECOND);
 
3060
                                                break;
 
3061
 
 
3062
                                        case DTK_MINUTE:
 
3063
                                                tm->tm_min += val;
 
3064
                                                if (fval != 0)
 
3065
                                                {
 
3066
                                                        int                     sec;
 
3067
 
 
3068
                                                        fval *= 60;
 
3069
                                                        sec = fval;
 
3070
                                                        tm->tm_sec += sec;
 
3071
#ifdef HAVE_INT64_TIMESTAMP
 
3072
                                                        *fsec += ((fval - sec) * 1000000);
 
3073
#else
 
3074
                                                        *fsec += (fval - sec);
 
3075
#endif
 
3076
                                                }
 
3077
                                                tmask = DTK_M(MINUTE);
 
3078
                                                break;
 
3079
 
 
3080
                                        case DTK_HOUR:
 
3081
                                                tm->tm_hour += val;
 
3082
                                                if (fval != 0)
 
3083
                                                {
 
3084
                                                        int                     sec;
 
3085
 
 
3086
                                                        fval *= 3600;
 
3087
                                                        sec = fval;
 
3088
                                                        tm->tm_sec += sec;
 
3089
#ifdef HAVE_INT64_TIMESTAMP
 
3090
                                                        *fsec += ((fval - sec) * 1000000);
 
3091
#else
 
3092
                                                        *fsec += (fval - sec);
 
3093
#endif
 
3094
                                                }
 
3095
                                                tmask = DTK_M(HOUR);
 
3096
                                                break;
 
3097
 
 
3098
                                        case DTK_DAY:
 
3099
                                                tm->tm_mday += val;
 
3100
                                                if (fval != 0)
 
3101
                                                {
 
3102
                                                        int                     sec;
 
3103
 
 
3104
                                                        fval *= 86400;
 
3105
                                                        sec = fval;
 
3106
                                                        tm->tm_sec += sec;
 
3107
#ifdef HAVE_INT64_TIMESTAMP
 
3108
                                                        *fsec += ((fval - sec) * 1000000);
 
3109
#else
 
3110
                                                        *fsec += (fval - sec);
 
3111
#endif
 
3112
                                                }
 
3113
                                                tmask = ((fmask & DTK_M(DAY)) ? 0 : DTK_M(DAY));
 
3114
                                                break;
 
3115
 
 
3116
                                        case DTK_WEEK:
 
3117
                                                tm->tm_mday += val * 7;
 
3118
                                                if (fval != 0)
 
3119
                                                {
 
3120
                                                        int                     sec;
 
3121
 
 
3122
                                                        fval *= (7 * 86400);
 
3123
                                                        sec = fval;
 
3124
                                                        tm->tm_sec += sec;
 
3125
#ifdef HAVE_INT64_TIMESTAMP
 
3126
                                                        *fsec += ((fval - sec) * 1000000);
 
3127
#else
 
3128
                                                        *fsec += (fval - sec);
 
3129
#endif
 
3130
                                                }
 
3131
                                                tmask = ((fmask & DTK_M(DAY)) ? 0 : DTK_M(DAY));
 
3132
                                                break;
 
3133
 
 
3134
                                        case DTK_MONTH:
 
3135
                                                tm->tm_mon += val;
 
3136
                                                if (fval != 0)
 
3137
                                                {
 
3138
                                                        int                     sec;
 
3139
 
 
3140
                                                        fval *= (30 * 86400);
 
3141
                                                        sec = fval;
 
3142
                                                        tm->tm_sec += sec;
 
3143
#ifdef HAVE_INT64_TIMESTAMP
 
3144
                                                        *fsec += ((fval - sec) * 1000000);
 
3145
#else
 
3146
                                                        *fsec += (fval - sec);
 
3147
#endif
 
3148
                                                }
 
3149
                                                tmask = DTK_M(MONTH);
 
3150
                                                break;
 
3151
 
 
3152
                                        case DTK_YEAR:
 
3153
                                                tm->tm_year += val;
 
3154
                                                if (fval != 0)
 
3155
                                                        tm->tm_mon += (fval * 12);
 
3156
                                                tmask = ((fmask & DTK_M(YEAR)) ? 0 : DTK_M(YEAR));
 
3157
                                                break;
 
3158
 
 
3159
                                        case DTK_DECADE:
 
3160
                                                tm->tm_year += val * 10;
 
3161
                                                if (fval != 0)
 
3162
                                                        tm->tm_mon += (fval * 120);
 
3163
                                                tmask = ((fmask & DTK_M(YEAR)) ? 0 : DTK_M(YEAR));
 
3164
                                                break;
 
3165
 
 
3166
                                        case DTK_CENTURY:
 
3167
                                                tm->tm_year += val * 100;
 
3168
                                                if (fval != 0)
 
3169
                                                        tm->tm_mon += (fval * 1200);
 
3170
                                                tmask = ((fmask & DTK_M(YEAR)) ? 0 : DTK_M(YEAR));
 
3171
                                                break;
 
3172
 
 
3173
                                        case DTK_MILLENNIUM:
 
3174
                                                tm->tm_year += val * 1000;
 
3175
                                                if (fval != 0)
 
3176
                                                        tm->tm_mon += (fval * 12000);
 
3177
                                                tmask = ((fmask & DTK_M(YEAR)) ? 0 : DTK_M(YEAR));
 
3178
                                                break;
 
3179
 
 
3180
                                        default:
 
3181
                                                return DTERR_BAD_FORMAT;
 
3182
                                }
 
3183
                                break;
 
3184
 
 
3185
                        case DTK_STRING:
 
3186
                        case DTK_SPECIAL:
 
3187
                                type = DecodeUnits(i, field[i], &val);
 
3188
                                if (type == IGNORE_DTF)
 
3189
                                        continue;
 
3190
 
 
3191
                                tmask = 0;              /* DTK_M(type); */
 
3192
                                switch (type)
 
3193
                                {
 
3194
                                        case UNITS:
 
3195
                                                type = val;
 
3196
                                                break;
 
3197
 
 
3198
                                        case AGO:
 
3199
                                                is_before = TRUE;
 
3200
                                                type = val;
 
3201
                                                break;
 
3202
 
 
3203
                                        case RESERV:
 
3204
                                                tmask = (DTK_DATE_M || DTK_TIME_M);
 
3205
                                                *dtype = val;
 
3206
                                                break;
 
3207
 
 
3208
                                        default:
 
3209
                                                return DTERR_BAD_FORMAT;
 
3210
                                }
 
3211
                                break;
 
3212
 
 
3213
                        default:
 
3214
                                return DTERR_BAD_FORMAT;
 
3215
                }
 
3216
 
 
3217
                if (tmask & fmask)
 
3218
                        return DTERR_BAD_FORMAT;
 
3219
                fmask |= tmask;
 
3220
        }
 
3221
 
 
3222
        if (*fsec != 0)
 
3223
        {
 
3224
                int                     sec;
 
3225
 
 
3226
#ifdef HAVE_INT64_TIMESTAMP
 
3227
                sec = (*fsec / INT64CONST(1000000));
 
3228
                *fsec -= (sec * INT64CONST(1000000));
 
3229
#else
 
3230
                TMODULO(*fsec, sec, 1e0);
 
3231
#endif
 
3232
                tm->tm_sec += sec;
 
3233
        }
 
3234
 
 
3235
        if (is_before)
 
3236
        {
 
3237
                *fsec = -(*fsec);
 
3238
                tm->tm_sec = -(tm->tm_sec);
 
3239
                tm->tm_min = -(tm->tm_min);
 
3240
                tm->tm_hour = -(tm->tm_hour);
 
3241
                tm->tm_mday = -(tm->tm_mday);
 
3242
                tm->tm_mon = -(tm->tm_mon);
 
3243
                tm->tm_year = -(tm->tm_year);
 
3244
        }
 
3245
 
 
3246
        /* ensure that at least one time field has been found */
 
3247
        if (fmask == 0)
 
3248
                return DTERR_BAD_FORMAT;
 
3249
 
 
3250
        return 0;
 
3251
}
 
3252
 
 
3253
 
 
3254
/* DecodeUnits()
 
3255
 * Decode text string using lookup table.
 
3256
 * This routine supports time interval decoding.
 
3257
 */
 
3258
int
 
3259
DecodeUnits(int field, char *lowtoken, int *val)
 
3260
{
 
3261
        int                     type;
 
3262
        datetkn    *tp;
 
3263
 
 
3264
        if ((deltacache[field] != NULL)
 
3265
                && (strncmp(lowtoken, deltacache[field]->token, TOKMAXLEN) == 0))
 
3266
                tp = deltacache[field];
 
3267
        else
 
3268
                tp = datebsearch(lowtoken, deltatktbl, szdeltatktbl);
 
3269
        deltacache[field] = tp;
 
3270
        if (tp == NULL)
 
3271
        {
 
3272
                type = UNKNOWN_FIELD;
 
3273
                *val = 0;
 
3274
        }
 
3275
        else
 
3276
        {
 
3277
                type = tp->type;
 
3278
                if ((type == TZ) || (type == DTZ))
 
3279
                        *val = FROMVAL(tp);
 
3280
                else
 
3281
                        *val = tp->value;
 
3282
        }
 
3283
 
 
3284
        return type;
 
3285
}       /* DecodeUnits() */
 
3286
 
 
3287
/*
 
3288
 * Report an error detected by one of the datetime input processing routines.
 
3289
 *
 
3290
 * dterr is the error code, str is the original input string, datatype is
 
3291
 * the name of the datatype we were trying to accept.
 
3292
 *
 
3293
 * Note: it might seem useless to distinguish DTERR_INTERVAL_OVERFLOW and
 
3294
 * DTERR_TZDISP_OVERFLOW from DTERR_FIELD_OVERFLOW, but SQL99 mandates three
 
3295
 * separate SQLSTATE codes, so ...
 
3296
 */
 
3297
void
 
3298
DateTimeParseError(int dterr, const char *str, const char *datatype)
 
3299
{
 
3300
        switch (dterr)
 
3301
        {
 
3302
                case DTERR_FIELD_OVERFLOW:
 
3303
                        ereport(ERROR,
 
3304
                                        (errcode(ERRCODE_DATETIME_FIELD_OVERFLOW),
 
3305
                                         errmsg("date/time field value out of range: \"%s\"",
 
3306
                                                        str)));
 
3307
                        break;
 
3308
                case DTERR_MD_FIELD_OVERFLOW:
 
3309
                        /* <nanny>same as above, but add hint about DateStyle</nanny> */
 
3310
                        ereport(ERROR,
 
3311
                                        (errcode(ERRCODE_DATETIME_FIELD_OVERFLOW),
 
3312
                                         errmsg("date/time field value out of range: \"%s\"",
 
3313
                                                        str),
 
3314
                                         errhint("Perhaps you need a different \"datestyle\" setting.")));
 
3315
                        break;
 
3316
                case DTERR_INTERVAL_OVERFLOW:
 
3317
                        ereport(ERROR,
 
3318
                                        (errcode(ERRCODE_INTERVAL_FIELD_OVERFLOW),
 
3319
                                         errmsg("interval field value out of range: \"%s\"",
 
3320
                                                        str)));
 
3321
                        break;
 
3322
                case DTERR_TZDISP_OVERFLOW:
 
3323
                        ereport(ERROR,
 
3324
                                  (errcode(ERRCODE_INVALID_TIME_ZONE_DISPLACEMENT_VALUE),
 
3325
                                   errmsg("time zone displacement out of range: \"%s\"",
 
3326
                                                  str)));
 
3327
                        break;
 
3328
                case DTERR_BAD_FORMAT:
 
3329
                default:
 
3330
                        ereport(ERROR,
 
3331
                                        (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
 
3332
                                         errmsg("invalid input syntax for type %s: \"%s\"",
 
3333
                                                        datatype, str)));
 
3334
                        break;
 
3335
        }
 
3336
}
 
3337
 
 
3338
/* datebsearch()
 
3339
 * Binary search -- from Knuth (6.2.1) Algorithm B.  Special case like this
 
3340
 * is WAY faster than the generic bsearch().
 
3341
 */
 
3342
static datetkn *
 
3343
datebsearch(char *key, datetkn *base, unsigned int nel)
 
3344
{
 
3345
        datetkn    *last = base + nel - 1,
 
3346
                           *position;
 
3347
        int                     result;
 
3348
 
 
3349
        while (last >= base)
 
3350
        {
 
3351
                position = base + ((last - base) >> 1);
 
3352
                result = key[0] - position->token[0];
 
3353
                if (result == 0)
 
3354
                {
 
3355
                        result = strncmp(key, position->token, TOKMAXLEN);
 
3356
                        if (result == 0)
 
3357
                                return position;
 
3358
                }
 
3359
                if (result < 0)
 
3360
                        last = position - 1;
 
3361
                else
 
3362
                        base = position + 1;
 
3363
        }
 
3364
        return NULL;
 
3365
}
 
3366
 
 
3367
 
 
3368
/* EncodeDateOnly()
 
3369
 * Encode date as local time.
 
3370
 */
 
3371
int
 
3372
EncodeDateOnly(struct pg_tm * tm, int style, char *str)
 
3373
{
 
3374
        if ((tm->tm_mon < 1) || (tm->tm_mon > 12))
 
3375
                return -1;
 
3376
 
 
3377
        switch (style)
 
3378
        {
 
3379
                case USE_ISO_DATES:
 
3380
                        /* compatible with ISO date formats */
 
3381
                        if (tm->tm_year > 0)
 
3382
                                sprintf(str, "%04d-%02d-%02d",
 
3383
                                                tm->tm_year, tm->tm_mon, tm->tm_mday);
 
3384
                        else
 
3385
                                sprintf(str, "%04d-%02d-%02d %s",
 
3386
                                          -(tm->tm_year - 1), tm->tm_mon, tm->tm_mday, "BC");
 
3387
                        break;
 
3388
 
 
3389
                case USE_SQL_DATES:
 
3390
                        /* compatible with Oracle/Ingres date formats */
 
3391
                        if (DateOrder == DATEORDER_DMY)
 
3392
                                sprintf(str, "%02d/%02d", tm->tm_mday, tm->tm_mon);
 
3393
                        else
 
3394
                                sprintf(str, "%02d/%02d", tm->tm_mon, tm->tm_mday);
 
3395
                        if (tm->tm_year > 0)
 
3396
                                sprintf((str + 5), "/%04d", tm->tm_year);
 
3397
                        else
 
3398
                                sprintf((str + 5), "/%04d %s", -(tm->tm_year - 1), "BC");
 
3399
                        break;
 
3400
 
 
3401
                case USE_GERMAN_DATES:
 
3402
                        /* German-style date format */
 
3403
                        sprintf(str, "%02d.%02d", tm->tm_mday, tm->tm_mon);
 
3404
                        if (tm->tm_year > 0)
 
3405
                                sprintf((str + 5), ".%04d", tm->tm_year);
 
3406
                        else
 
3407
                                sprintf((str + 5), ".%04d %s", -(tm->tm_year - 1), "BC");
 
3408
                        break;
 
3409
 
 
3410
                case USE_POSTGRES_DATES:
 
3411
                default:
 
3412
                        /* traditional date-only style for Postgres */
 
3413
                        if (DateOrder == DATEORDER_DMY)
 
3414
                                sprintf(str, "%02d-%02d", tm->tm_mday, tm->tm_mon);
 
3415
                        else
 
3416
                                sprintf(str, "%02d-%02d", tm->tm_mon, tm->tm_mday);
 
3417
                        if (tm->tm_year > 0)
 
3418
                                sprintf((str + 5), "-%04d", tm->tm_year);
 
3419
                        else
 
3420
                                sprintf((str + 5), "-%04d %s", -(tm->tm_year - 1), "BC");
 
3421
                        break;
 
3422
        }
 
3423
 
 
3424
        return TRUE;
 
3425
}       /* EncodeDateOnly() */
 
3426
 
 
3427
 
 
3428
/* EncodeTimeOnly()
 
3429
 * Encode time fields only.
 
3430
 */
 
3431
int
 
3432
EncodeTimeOnly(struct pg_tm * tm, fsec_t fsec, int *tzp, int style, char *str)
 
3433
{
 
3434
        if ((tm->tm_hour < 0) || (tm->tm_hour > 24))
 
3435
                return -1;
 
3436
 
 
3437
        sprintf(str, "%02d:%02d", tm->tm_hour, tm->tm_min);
 
3438
 
 
3439
        /*
 
3440
         * Print fractional seconds if any.  The field widths here should be
 
3441
         * at least equal to the larger of MAX_TIME_PRECISION and
 
3442
         * MAX_TIMESTAMP_PRECISION.
 
3443
         */
 
3444
        if (fsec != 0)
 
3445
        {
 
3446
#ifdef HAVE_INT64_TIMESTAMP
 
3447
                sprintf((str + strlen(str)), ":%02d.%06d", tm->tm_sec, fsec);
 
3448
#else
 
3449
                sprintf((str + strlen(str)), ":%013.10f", tm->tm_sec + fsec);
 
3450
#endif
 
3451
                /* chop off trailing pairs of zeros... */
 
3452
                while ((strcmp((str + strlen(str) - 2), "00") == 0)
 
3453
                           && (*(str + strlen(str) - 3) != '.'))
 
3454
                        *(str + strlen(str) - 2) = '\0';
 
3455
        }
 
3456
        else
 
3457
                sprintf((str + strlen(str)), ":%02d", tm->tm_sec);
 
3458
 
 
3459
        if (tzp != NULL)
 
3460
        {
 
3461
                int                     hour,
 
3462
                                        min;
 
3463
 
 
3464
                hour = -(*tzp / 3600);
 
3465
                min = ((abs(*tzp) / 60) % 60);
 
3466
                sprintf((str + strlen(str)), ((min != 0) ? "%+03d:%02d" : "%+03d"), hour, min);
 
3467
        }
 
3468
 
 
3469
        return TRUE;
 
3470
}       /* EncodeTimeOnly() */
 
3471
 
 
3472
 
 
3473
/* EncodeDateTime()
 
3474
 * Encode date and time interpreted as local time.
 
3475
 * Support several date styles:
 
3476
 *      Postgres - day mon hh:mm:ss yyyy tz
 
3477
 *      SQL - mm/dd/yyyy hh:mm:ss.ss tz
 
3478
 *      ISO - yyyy-mm-dd hh:mm:ss+/-tz
 
3479
 *      German - dd.mm.yyyy hh:mm:ss tz
 
3480
 * Variants (affects order of month and day for Postgres and SQL styles):
 
3481
 *      US - mm/dd/yyyy
 
3482
 *      European - dd/mm/yyyy
 
3483
 */
 
3484
int
 
3485
EncodeDateTime(struct pg_tm * tm, fsec_t fsec, int *tzp, char **tzn, int style, char *str)
 
3486
{
 
3487
        int                     day,
 
3488
                                hour,
 
3489
                                min;
 
3490
 
 
3491
        /*
 
3492
         * Why are we checking only the month field? Change this to an
 
3493
         * assert... if ((tm->tm_mon < 1) || (tm->tm_mon > 12)) return -1;
 
3494
         */
 
3495
        Assert((tm->tm_mon >= 1) && (tm->tm_mon <= 12));
 
3496
 
 
3497
        switch (style)
 
3498
        {
 
3499
                case USE_ISO_DATES:
 
3500
                        /* Compatible with ISO-8601 date formats */
 
3501
 
 
3502
                        sprintf(str, "%04d-%02d-%02d %02d:%02d",
 
3503
                                  ((tm->tm_year > 0) ? tm->tm_year : -(tm->tm_year - 1)),
 
3504
                                        tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min);
 
3505
 
 
3506
                        /*
 
3507
                         * Print fractional seconds if any.  The field widths here
 
3508
                         * should be at least equal to MAX_TIMESTAMP_PRECISION.
 
3509
                         *
 
3510
                         * In float mode, don't print fractional seconds before 1 AD,
 
3511
                         * since it's unlikely there's any precision left ...
 
3512
                         */
 
3513
#ifdef HAVE_INT64_TIMESTAMP
 
3514
                        if (fsec != 0)
 
3515
                        {
 
3516
                                sprintf((str + strlen(str)), ":%02d.%06d", tm->tm_sec, fsec);
 
3517
                                TrimTrailingZeros(str);
 
3518
                        }
 
3519
#else
 
3520
                        if ((fsec != 0) && (tm->tm_year > 0))
 
3521
                        {
 
3522
                                sprintf((str + strlen(str)), ":%09.6f", tm->tm_sec + fsec);
 
3523
                                TrimTrailingZeros(str);
 
3524
                        }
 
3525
#endif
 
3526
                        else
 
3527
                                sprintf((str + strlen(str)), ":%02d", tm->tm_sec);
 
3528
 
 
3529
                        /*
 
3530
                         * tzp == NULL indicates that we don't want *any* time zone
 
3531
                         * info in the output string. *tzn != NULL indicates that we
 
3532
                         * have alpha time zone info available. tm_isdst != -1
 
3533
                         * indicates that we have a valid time zone translation.
 
3534
                         */
 
3535
                        if ((tzp != NULL) && (tm->tm_isdst >= 0))
 
3536
                        {
 
3537
                                hour = -(*tzp / 3600);
 
3538
                                min = ((abs(*tzp) / 60) % 60);
 
3539
                                sprintf((str + strlen(str)), ((min != 0) ? "%+03d:%02d" : "%+03d"), hour, min);
 
3540
                        }
 
3541
 
 
3542
                        if (tm->tm_year <= 0)
 
3543
                                sprintf((str + strlen(str)), " BC");
 
3544
                        break;
 
3545
 
 
3546
                case USE_SQL_DATES:
 
3547
                        /* Compatible with Oracle/Ingres date formats */
 
3548
 
 
3549
                        if (DateOrder == DATEORDER_DMY)
 
3550
                                sprintf(str, "%02d/%02d", tm->tm_mday, tm->tm_mon);
 
3551
                        else
 
3552
                                sprintf(str, "%02d/%02d", tm->tm_mon, tm->tm_mday);
 
3553
 
 
3554
                        sprintf((str + 5), "/%04d %02d:%02d",
 
3555
                                  ((tm->tm_year > 0) ? tm->tm_year : -(tm->tm_year - 1)),
 
3556
                                        tm->tm_hour, tm->tm_min);
 
3557
 
 
3558
                        /*
 
3559
                         * Print fractional seconds if any.  The field widths here
 
3560
                         * should be at least equal to MAX_TIMESTAMP_PRECISION.
 
3561
                         *
 
3562
                         * In float mode, don't print fractional seconds before 1 AD,
 
3563
                         * since it's unlikely there's any precision left ...
 
3564
                         */
 
3565
#ifdef HAVE_INT64_TIMESTAMP
 
3566
                        if (fsec != 0)
 
3567
                        {
 
3568
                                sprintf((str + strlen(str)), ":%02d.%06d", tm->tm_sec, fsec);
 
3569
                                TrimTrailingZeros(str);
 
3570
                        }
 
3571
#else
 
3572
                        if ((fsec != 0) && (tm->tm_year > 0))
 
3573
                        {
 
3574
                                sprintf((str + strlen(str)), ":%09.6f", tm->tm_sec + fsec);
 
3575
                                TrimTrailingZeros(str);
 
3576
                        }
 
3577
#endif
 
3578
                        else
 
3579
                                sprintf((str + strlen(str)), ":%02d", tm->tm_sec);
 
3580
 
 
3581
                        if ((tzp != NULL) && (tm->tm_isdst >= 0))
 
3582
                        {
 
3583
                                if (*tzn != NULL)
 
3584
                                        sprintf((str + strlen(str)), " %.*s", MAXTZLEN, *tzn);
 
3585
                                else
 
3586
                                {
 
3587
                                        hour = -(*tzp / 3600);
 
3588
                                        min = ((abs(*tzp) / 60) % 60);
 
3589
                                        sprintf((str + strlen(str)), ((min != 0) ? "%+03d:%02d" : "%+03d"), hour, min);
 
3590
                                }
 
3591
                        }
 
3592
 
 
3593
                        if (tm->tm_year <= 0)
 
3594
                                sprintf((str + strlen(str)), " BC");
 
3595
                        break;
 
3596
 
 
3597
                case USE_GERMAN_DATES:
 
3598
                        /* German variant on European style */
 
3599
 
 
3600
                        sprintf(str, "%02d.%02d", tm->tm_mday, tm->tm_mon);
 
3601
 
 
3602
                        sprintf((str + 5), ".%04d %02d:%02d",
 
3603
                                  ((tm->tm_year > 0) ? tm->tm_year : -(tm->tm_year - 1)),
 
3604
                                        tm->tm_hour, tm->tm_min);
 
3605
 
 
3606
                        /*
 
3607
                         * Print fractional seconds if any.  The field widths here
 
3608
                         * should be at least equal to MAX_TIMESTAMP_PRECISION.
 
3609
                         *
 
3610
                         * In float mode, don't print fractional seconds before 1 AD,
 
3611
                         * since it's unlikely there's any precision left ...
 
3612
                         */
 
3613
#ifdef HAVE_INT64_TIMESTAMP
 
3614
                        if (fsec != 0)
 
3615
                        {
 
3616
                                sprintf((str + strlen(str)), ":%02d.%06d", tm->tm_sec, fsec);
 
3617
                                TrimTrailingZeros(str);
 
3618
                        }
 
3619
#else
 
3620
                        if ((fsec != 0) && (tm->tm_year > 0))
 
3621
                        {
 
3622
                                sprintf((str + strlen(str)), ":%09.6f", tm->tm_sec + fsec);
 
3623
                                TrimTrailingZeros(str);
 
3624
                        }
 
3625
#endif
 
3626
                        else
 
3627
                                sprintf((str + strlen(str)), ":%02d", tm->tm_sec);
 
3628
 
 
3629
                        if ((tzp != NULL) && (tm->tm_isdst >= 0))
 
3630
                        {
 
3631
                                if (*tzn != NULL)
 
3632
                                        sprintf((str + strlen(str)), " %.*s", MAXTZLEN, *tzn);
 
3633
                                else
 
3634
                                {
 
3635
                                        hour = -(*tzp / 3600);
 
3636
                                        min = ((abs(*tzp) / 60) % 60);
 
3637
                                        sprintf((str + strlen(str)), ((min != 0) ? "%+03d:%02d" : "%+03d"), hour, min);
 
3638
                                }
 
3639
                        }
 
3640
 
 
3641
                        if (tm->tm_year <= 0)
 
3642
                                sprintf((str + strlen(str)), " BC");
 
3643
                        break;
 
3644
 
 
3645
                case USE_POSTGRES_DATES:
 
3646
                default:
 
3647
                        /* Backward-compatible with traditional Postgres abstime dates */
 
3648
 
 
3649
                        day = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday);
 
3650
                        tm->tm_wday = j2day(day);
 
3651
 
 
3652
                        strncpy(str, days[tm->tm_wday], 3);
 
3653
                        strcpy((str + 3), " ");
 
3654
 
 
3655
                        if (DateOrder == DATEORDER_DMY)
 
3656
                                sprintf((str + 4), "%02d %3s", tm->tm_mday, months[tm->tm_mon - 1]);
 
3657
                        else
 
3658
                                sprintf((str + 4), "%3s %02d", months[tm->tm_mon - 1], tm->tm_mday);
 
3659
 
 
3660
                        sprintf((str + 10), " %02d:%02d", tm->tm_hour, tm->tm_min);
 
3661
 
 
3662
                        /*
 
3663
                         * Print fractional seconds if any.  The field widths here
 
3664
                         * should be at least equal to MAX_TIMESTAMP_PRECISION.
 
3665
                         *
 
3666
                         * In float mode, don't print fractional seconds before 1 AD,
 
3667
                         * since it's unlikely there's any precision left ...
 
3668
                         */
 
3669
#ifdef HAVE_INT64_TIMESTAMP
 
3670
                        if (fsec != 0)
 
3671
                        {
 
3672
                                sprintf((str + strlen(str)), ":%02d.%06d", tm->tm_sec, fsec);
 
3673
                                TrimTrailingZeros(str);
 
3674
                        }
 
3675
#else
 
3676
                        if ((fsec != 0) && (tm->tm_year > 0))
 
3677
                        {
 
3678
                                sprintf((str + strlen(str)), ":%09.6f", tm->tm_sec + fsec);
 
3679
                                TrimTrailingZeros(str);
 
3680
                        }
 
3681
#endif
 
3682
                        else
 
3683
                                sprintf((str + strlen(str)), ":%02d", tm->tm_sec);
 
3684
 
 
3685
                        sprintf((str + strlen(str)), " %04d",
 
3686
                                 ((tm->tm_year > 0) ? tm->tm_year : -(tm->tm_year - 1)));
 
3687
 
 
3688
                        if ((tzp != NULL) && (tm->tm_isdst >= 0))
 
3689
                        {
 
3690
                                if (*tzn != NULL)
 
3691
                                        sprintf((str + strlen(str)), " %.*s", MAXTZLEN, *tzn);
 
3692
                                else
 
3693
                                {
 
3694
                                        /*
 
3695
                                         * We have a time zone, but no string version. Use the
 
3696
                                         * numeric form, but be sure to include a leading
 
3697
                                         * space to avoid formatting something which would be
 
3698
                                         * rejected by the date/time parser later. - thomas
 
3699
                                         * 2001-10-19
 
3700
                                         */
 
3701
                                        hour = -(*tzp / 3600);
 
3702
                                        min = ((abs(*tzp) / 60) % 60);
 
3703
                                        sprintf((str + strlen(str)), ((min != 0) ? " %+03d:%02d" : " %+03d"), hour, min);
 
3704
                                }
 
3705
                        }
 
3706
 
 
3707
                        if (tm->tm_year <= 0)
 
3708
                                sprintf((str + strlen(str)), " BC");
 
3709
                        break;
 
3710
        }
 
3711
 
 
3712
        return TRUE;
 
3713
}
 
3714
 
 
3715
 
 
3716
/* EncodeInterval()
 
3717
 * Interpret time structure as a delta time and convert to string.
 
3718
 *
 
3719
 * Support "traditional Postgres" and ISO-8601 styles.
 
3720
 * Actually, afaik ISO does not address time interval formatting,
 
3721
 *      but this looks similar to the spec for absolute date/time.
 
3722
 * - thomas 1998-04-30
 
3723
 */
 
3724
int
 
3725
EncodeInterval(struct pg_tm * tm, fsec_t fsec, int style, char *str)
 
3726
{
 
3727
        int                     is_before = FALSE;
 
3728
        int                     is_nonzero = FALSE;
 
3729
        char       *cp = str;
 
3730
 
 
3731
        /*
 
3732
         * The sign of year and month are guaranteed to match, since they are
 
3733
         * stored internally as "month". But we'll need to check for is_before
 
3734
         * and is_nonzero when determining the signs of hour/minute/seconds
 
3735
         * fields.
 
3736
         */
 
3737
        switch (style)
 
3738
        {
 
3739
                        /* compatible with ISO date formats */
 
3740
                case USE_ISO_DATES:
 
3741
                        if (tm->tm_year != 0)
 
3742
                        {
 
3743
                                sprintf(cp, "%d year%s",
 
3744
                                                tm->tm_year, ((tm->tm_year != 1) ? "s" : ""));
 
3745
                                cp += strlen(cp);
 
3746
                                is_before = (tm->tm_year < 0);
 
3747
                                is_nonzero = TRUE;
 
3748
                        }
 
3749
 
 
3750
                        if (tm->tm_mon != 0)
 
3751
                        {
 
3752
                                sprintf(cp, "%s%s%d mon%s", (is_nonzero ? " " : ""),
 
3753
                                                ((is_before && (tm->tm_mon > 0)) ? "+" : ""),
 
3754
                                                tm->tm_mon, ((tm->tm_mon != 1) ? "s" : ""));
 
3755
                                cp += strlen(cp);
 
3756
                                is_before = (tm->tm_mon < 0);
 
3757
                                is_nonzero = TRUE;
 
3758
                        }
 
3759
 
 
3760
                        if (tm->tm_mday != 0)
 
3761
                        {
 
3762
                                sprintf(cp, "%s%s%d day%s", (is_nonzero ? " " : ""),
 
3763
                                                ((is_before && (tm->tm_mday > 0)) ? "+" : ""),
 
3764
                                                tm->tm_mday, ((tm->tm_mday != 1) ? "s" : ""));
 
3765
                                cp += strlen(cp);
 
3766
                                is_before = (tm->tm_mday < 0);
 
3767
                                is_nonzero = TRUE;
 
3768
                        }
 
3769
 
 
3770
                        if ((!is_nonzero) || (tm->tm_hour != 0) || (tm->tm_min != 0)
 
3771
                                || (tm->tm_sec != 0) || (fsec != 0))
 
3772
                        {
 
3773
                                int                     minus = ((tm->tm_hour < 0) || (tm->tm_min < 0)
 
3774
                                                                         || (tm->tm_sec < 0) || (fsec < 0));
 
3775
 
 
3776
                                sprintf(cp, "%s%s%02d:%02d", (is_nonzero ? " " : ""),
 
3777
                                                (minus ? "-" : (is_before ? "+" : "")),
 
3778
                                                abs(tm->tm_hour), abs(tm->tm_min));
 
3779
                                cp += strlen(cp);
 
3780
                                /* Mark as "non-zero" since the fields are now filled in */
 
3781
                                is_nonzero = TRUE;
 
3782
 
 
3783
                                /* need fractional seconds? */
 
3784
                                if (fsec != 0)
 
3785
                                {
 
3786
#ifdef HAVE_INT64_TIMESTAMP
 
3787
                                        sprintf(cp, ":%02d", abs(tm->tm_sec));
 
3788
                                        cp += strlen(cp);
 
3789
                                        sprintf(cp, ".%06d", ((fsec >= 0) ? fsec : -(fsec)));
 
3790
#else
 
3791
                                        fsec += tm->tm_sec;
 
3792
                                        sprintf(cp, ":%013.10f", fabs(fsec));
 
3793
#endif
 
3794
                                        TrimTrailingZeros(cp);
 
3795
                                        cp += strlen(cp);
 
3796
                                }
 
3797
                                else
 
3798
                                {
 
3799
                                        sprintf(cp, ":%02d", abs(tm->tm_sec));
 
3800
                                        cp += strlen(cp);
 
3801
                                }
 
3802
                        }
 
3803
                        break;
 
3804
 
 
3805
                case USE_POSTGRES_DATES:
 
3806
                default:
 
3807
                        strcpy(cp, "@ ");
 
3808
                        cp += strlen(cp);
 
3809
 
 
3810
                        if (tm->tm_year != 0)
 
3811
                        {
 
3812
                                int                     year = tm->tm_year;
 
3813
 
 
3814
                                if (tm->tm_year < 0)
 
3815
                                        year = -year;
 
3816
 
 
3817
                                sprintf(cp, "%d year%s", year,
 
3818
                                                ((year != 1) ? "s" : ""));
 
3819
                                cp += strlen(cp);
 
3820
                                is_before = (tm->tm_year < 0);
 
3821
                                is_nonzero = TRUE;
 
3822
                        }
 
3823
 
 
3824
                        if (tm->tm_mon != 0)
 
3825
                        {
 
3826
                                int                     mon = tm->tm_mon;
 
3827
 
 
3828
                                if (is_before || ((!is_nonzero) && (tm->tm_mon < 0)))
 
3829
                                        mon = -mon;
 
3830
 
 
3831
                                sprintf(cp, "%s%d mon%s", (is_nonzero ? " " : ""), mon,
 
3832
                                                ((mon != 1) ? "s" : ""));
 
3833
                                cp += strlen(cp);
 
3834
                                if (!is_nonzero)
 
3835
                                        is_before = (tm->tm_mon < 0);
 
3836
                                is_nonzero = TRUE;
 
3837
                        }
 
3838
 
 
3839
                        if (tm->tm_mday != 0)
 
3840
                        {
 
3841
                                int                     day = tm->tm_mday;
 
3842
 
 
3843
                                if (is_before || ((!is_nonzero) && (tm->tm_mday < 0)))
 
3844
                                        day = -day;
 
3845
 
 
3846
                                sprintf(cp, "%s%d day%s", (is_nonzero ? " " : ""), day,
 
3847
                                                ((day != 1) ? "s" : ""));
 
3848
                                cp += strlen(cp);
 
3849
                                if (!is_nonzero)
 
3850
                                        is_before = (tm->tm_mday < 0);
 
3851
                                is_nonzero = TRUE;
 
3852
                        }
 
3853
                        if (tm->tm_hour != 0)
 
3854
                        {
 
3855
                                int                     hour = tm->tm_hour;
 
3856
 
 
3857
                                if (is_before || ((!is_nonzero) && (tm->tm_hour < 0)))
 
3858
                                        hour = -hour;
 
3859
 
 
3860
                                sprintf(cp, "%s%d hour%s", (is_nonzero ? " " : ""), hour,
 
3861
                                                ((hour != 1) ? "s" : ""));
 
3862
                                cp += strlen(cp);
 
3863
                                if (!is_nonzero)
 
3864
                                        is_before = (tm->tm_hour < 0);
 
3865
                                is_nonzero = TRUE;
 
3866
                        }
 
3867
 
 
3868
                        if (tm->tm_min != 0)
 
3869
                        {
 
3870
                                int                     min = tm->tm_min;
 
3871
 
 
3872
                                if (is_before || ((!is_nonzero) && (tm->tm_min < 0)))
 
3873
                                        min = -min;
 
3874
 
 
3875
                                sprintf(cp, "%s%d min%s", (is_nonzero ? " " : ""), min,
 
3876
                                                ((min != 1) ? "s" : ""));
 
3877
                                cp += strlen(cp);
 
3878
                                if (!is_nonzero)
 
3879
                                        is_before = (tm->tm_min < 0);
 
3880
                                is_nonzero = TRUE;
 
3881
                        }
 
3882
 
 
3883
                        /* fractional seconds? */
 
3884
                        if (fsec != 0)
 
3885
                        {
 
3886
                                fsec_t          sec;
 
3887
 
 
3888
#ifdef HAVE_INT64_TIMESTAMP
 
3889
                                sec = fsec;
 
3890
                                if (is_before || ((!is_nonzero) && (tm->tm_sec < 0)))
 
3891
                                {
 
3892
                                        tm->tm_sec = -tm->tm_sec;
 
3893
                                        sec = -sec;
 
3894
                                        is_before = TRUE;
 
3895
                                }
 
3896
                                else if ((!is_nonzero) && (tm->tm_sec == 0) && (fsec < 0))
 
3897
                                {
 
3898
                                        sec = -sec;
 
3899
                                        is_before = TRUE;
 
3900
                                }
 
3901
                                sprintf(cp, "%s%d.%02d secs", (is_nonzero ? " " : ""),
 
3902
                                                tm->tm_sec, (((int) sec) / 10000));
 
3903
                                cp += strlen(cp);
 
3904
#else
 
3905
                                fsec += tm->tm_sec;
 
3906
                                sec = fsec;
 
3907
                                if (is_before || ((!is_nonzero) && (fsec < 0)))
 
3908
                                        sec = -sec;
 
3909
 
 
3910
                                sprintf(cp, "%s%.2f secs", (is_nonzero ? " " : ""), sec);
 
3911
                                cp += strlen(cp);
 
3912
                                if (!is_nonzero)
 
3913
                                        is_before = (fsec < 0);
 
3914
#endif
 
3915
                                is_nonzero = TRUE;
 
3916
                        }
 
3917
                        /* otherwise, integer seconds only? */
 
3918
                        else if (tm->tm_sec != 0)
 
3919
                        {
 
3920
                                int                     sec = tm->tm_sec;
 
3921
 
 
3922
                                if (is_before || ((!is_nonzero) && (tm->tm_sec < 0)))
 
3923
                                        sec = -sec;
 
3924
 
 
3925
                                sprintf(cp, "%s%d sec%s", (is_nonzero ? " " : ""), sec,
 
3926
                                                ((sec != 1) ? "s" : ""));
 
3927
                                cp += strlen(cp);
 
3928
                                if (!is_nonzero)
 
3929
                                        is_before = (tm->tm_sec < 0);
 
3930
                                is_nonzero = TRUE;
 
3931
                        }
 
3932
                        break;
 
3933
        }
 
3934
 
 
3935
        /* identically zero? then put in a unitless zero... */
 
3936
        if (!is_nonzero)
 
3937
        {
 
3938
                strcat(cp, "0");
 
3939
                cp += strlen(cp);
 
3940
        }
 
3941
 
 
3942
        if (is_before && (style != USE_ISO_DATES))
 
3943
        {
 
3944
                strcat(cp, " ago");
 
3945
                cp += strlen(cp);
 
3946
        }
 
3947
 
 
3948
        return 0;
 
3949
}       /* EncodeInterval() */
 
3950
 
 
3951
 
 
3952
/* GUC assign_hook for australian_timezones */
 
3953
bool
 
3954
ClearDateCache(bool newval, bool doit, GucSource source)
 
3955
{
 
3956
        int                     i;
 
3957
 
 
3958
        if (doit)
 
3959
        {
 
3960
                for (i = 0; i < MAXDATEFIELDS; i++)
 
3961
                        datecache[i] = NULL;
 
3962
        }
 
3963
 
 
3964
        return true;
 
3965
}
 
3966
 
 
3967
/*
 
3968
 * We've been burnt by stupid errors in the ordering of the datetkn tables
 
3969
 * once too often.      Arrange to check them during postmaster start.
 
3970
 */
 
3971
static bool
 
3972
CheckDateTokenTable(const char *tablename, datetkn *base, unsigned int nel)
 
3973
{
 
3974
        bool            ok = true;
 
3975
        unsigned int i;
 
3976
 
 
3977
        for (i = 1; i < nel; i++)
 
3978
        {
 
3979
                if (strncmp(base[i - 1].token, base[i].token, TOKMAXLEN) >= 0)
 
3980
                {
 
3981
                        elog(LOG, "ordering error in %s table: \"%.*s\" >= \"%.*s\"",
 
3982
                                 tablename,
 
3983
                                 TOKMAXLEN, base[i - 1].token,
 
3984
                                 TOKMAXLEN, base[i].token);
 
3985
                        ok = false;
 
3986
                }
 
3987
        }
 
3988
        return ok;
 
3989
}
 
3990
 
 
3991
bool
 
3992
CheckDateTokenTables(void)
 
3993
{
 
3994
        bool            ok = true;
 
3995
 
 
3996
        Assert(UNIX_EPOCH_JDATE == date2j(1970, 1, 1));
 
3997
        Assert(POSTGRES_EPOCH_JDATE == date2j(2000, 1, 1));
 
3998
 
 
3999
        ok &= CheckDateTokenTable("datetktbl", datetktbl, szdatetktbl);
 
4000
        ok &= CheckDateTokenTable("deltatktbl", deltatktbl, szdeltatktbl);
 
4001
        ok &= CheckDateTokenTable("australian_datetktbl",
 
4002
                                                          australian_datetktbl,
 
4003
                                                          australian_szdatetktbl);
 
4004
        return ok;
 
4005
}