00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "postgres.h"
00016
00017 #include <ctype.h>
00018 #include <float.h>
00019 #include <limits.h>
00020 #include <math.h>
00021
00022 #include "access/htup_details.h"
00023 #include "access/xact.h"
00024 #include "catalog/pg_type.h"
00025 #include "funcapi.h"
00026 #include "miscadmin.h"
00027 #include "nodes/nodeFuncs.h"
00028 #include "utils/builtins.h"
00029 #include "utils/date.h"
00030 #include "utils/datetime.h"
00031 #include "utils/memutils.h"
00032 #include "utils/tzparser.h"
00033
00034
00035 static int DecodeNumber(int flen, char *field, bool haveTextMonth,
00036 int fmask, int *tmask,
00037 struct pg_tm * tm, fsec_t *fsec, bool *is2digits);
00038 static int DecodeNumberField(int len, char *str,
00039 int fmask, int *tmask,
00040 struct pg_tm * tm, fsec_t *fsec, bool *is2digits);
00041 static int DecodeTime(char *str, int fmask, int range,
00042 int *tmask, struct pg_tm * tm, fsec_t *fsec);
00043 static int DecodeTimezone(char *str, int *tzp);
00044 static const datetkn *datebsearch(const char *key, const datetkn *base, int nel);
00045 static int DecodeDate(char *str, int fmask, int *tmask, bool *is2digits,
00046 struct pg_tm * tm);
00047 static int ValidateDate(int fmask, bool isjulian, bool is2digits, bool bc,
00048 struct pg_tm * tm);
00049 static void TrimTrailingZeros(char *str);
00050 static void AppendSeconds(char *cp, int sec, fsec_t fsec,
00051 int precision, bool fillzeros);
00052 static void AdjustFractSeconds(double frac, struct pg_tm * tm, fsec_t *fsec,
00053 int scale);
00054 static void AdjustFractDays(double frac, struct pg_tm * tm, fsec_t *fsec,
00055 int scale);
00056
00057
00058 const int day_tab[2][13] =
00059 {
00060 {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 0},
00061 {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 0}
00062 };
00063
00064 char *months[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
00065 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", NULL};
00066
00067 char *days[] = {"Sunday", "Monday", "Tuesday", "Wednesday",
00068 "Thursday", "Friday", "Saturday", NULL};
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080 #define ABS_SIGNBIT ((char) 0200)
00081 #define VALMASK ((char) 0177)
00082 #define POS(n) (n)
00083 #define NEG(n) ((n)|ABS_SIGNBIT)
00084 #define SIGNEDCHAR(c) ((c)&ABS_SIGNBIT? -((c)&VALMASK): (c))
00085 #define FROMVAL(tp) (-SIGNEDCHAR((tp)->value) * 15)
00086 #define TOVAL(tp, v) ((tp)->value = ((v) < 0? NEG((-(v))/15): POS(v)/15))
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107 static datetkn *timezonetktbl = NULL;
00108
00109 static int sztimezonetktbl = 0;
00110
00111 static const datetkn datetktbl[] = {
00112
00113 {EARLY, RESERV, DTK_EARLY},
00114 {DA_D, ADBC, AD},
00115 {"allballs", RESERV, DTK_ZULU},
00116 {"am", AMPM, AM},
00117 {"apr", MONTH, 4},
00118 {"april", MONTH, 4},
00119 {"at", IGNORE_DTF, 0},
00120 {"aug", MONTH, 8},
00121 {"august", MONTH, 8},
00122 {DB_C, ADBC, BC},
00123 {DCURRENT, RESERV, DTK_CURRENT},
00124 {"d", UNITS, DTK_DAY},
00125 {"dec", MONTH, 12},
00126 {"december", MONTH, 12},
00127 {"dow", RESERV, DTK_DOW},
00128 {"doy", RESERV, DTK_DOY},
00129 {"dst", DTZMOD, 6},
00130 {EPOCH, RESERV, DTK_EPOCH},
00131 {"feb", MONTH, 2},
00132 {"february", MONTH, 2},
00133 {"fri", DOW, 5},
00134 {"friday", DOW, 5},
00135 {"h", UNITS, DTK_HOUR},
00136 {LATE, RESERV, DTK_LATE},
00137 {INVALID, RESERV, DTK_INVALID},
00138 {"isodow", RESERV, DTK_ISODOW},
00139 {"isoyear", UNITS, DTK_ISOYEAR},
00140 {"j", UNITS, DTK_JULIAN},
00141 {"jan", MONTH, 1},
00142 {"january", MONTH, 1},
00143 {"jd", UNITS, DTK_JULIAN},
00144 {"jul", MONTH, 7},
00145 {"julian", UNITS, DTK_JULIAN},
00146 {"july", MONTH, 7},
00147 {"jun", MONTH, 6},
00148 {"june", MONTH, 6},
00149 {"m", UNITS, DTK_MONTH},
00150 {"mar", MONTH, 3},
00151 {"march", MONTH, 3},
00152 {"may", MONTH, 5},
00153 {"mm", UNITS, DTK_MINUTE},
00154 {"mon", DOW, 1},
00155 {"monday", DOW, 1},
00156 {"nov", MONTH, 11},
00157 {"november", MONTH, 11},
00158 {NOW, RESERV, DTK_NOW},
00159 {"oct", MONTH, 10},
00160 {"october", MONTH, 10},
00161 {"on", IGNORE_DTF, 0},
00162 {"pm", AMPM, PM},
00163 {"s", UNITS, DTK_SECOND},
00164 {"sat", DOW, 6},
00165 {"saturday", DOW, 6},
00166 {"sep", MONTH, 9},
00167 {"sept", MONTH, 9},
00168 {"september", MONTH, 9},
00169 {"sun", DOW, 0},
00170 {"sunday", DOW, 0},
00171 {"t", ISOTIME, DTK_TIME},
00172 {"thu", DOW, 4},
00173 {"thur", DOW, 4},
00174 {"thurs", DOW, 4},
00175 {"thursday", DOW, 4},
00176 {TODAY, RESERV, DTK_TODAY},
00177 {TOMORROW, RESERV, DTK_TOMORROW},
00178 {"tue", DOW, 2},
00179 {"tues", DOW, 2},
00180 {"tuesday", DOW, 2},
00181 {"undefined", RESERV, DTK_INVALID},
00182 {"wed", DOW, 3},
00183 {"wednesday", DOW, 3},
00184 {"weds", DOW, 3},
00185 {"y", UNITS, DTK_YEAR},
00186 {YESTERDAY, RESERV, DTK_YESTERDAY}
00187 };
00188
00189 static int szdatetktbl = sizeof datetktbl / sizeof datetktbl[0];
00190
00191 static datetkn deltatktbl[] = {
00192
00193 {"@", IGNORE_DTF, 0},
00194 {DAGO, AGO, 0},
00195 {"c", UNITS, DTK_CENTURY},
00196 {"cent", UNITS, DTK_CENTURY},
00197 {"centuries", UNITS, DTK_CENTURY},
00198 {DCENTURY, UNITS, DTK_CENTURY},
00199 {"d", UNITS, DTK_DAY},
00200 {DDAY, UNITS, DTK_DAY},
00201 {"days", UNITS, DTK_DAY},
00202 {"dec", UNITS, DTK_DECADE},
00203 {DDECADE, UNITS, DTK_DECADE},
00204 {"decades", UNITS, DTK_DECADE},
00205 {"decs", UNITS, DTK_DECADE},
00206 {"h", UNITS, DTK_HOUR},
00207 {DHOUR, UNITS, DTK_HOUR},
00208 {"hours", UNITS, DTK_HOUR},
00209 {"hr", UNITS, DTK_HOUR},
00210 {"hrs", UNITS, DTK_HOUR},
00211 {INVALID, RESERV, DTK_INVALID},
00212 {"m", UNITS, DTK_MINUTE},
00213 {"microsecon", UNITS, DTK_MICROSEC},
00214 {"mil", UNITS, DTK_MILLENNIUM},
00215 {"millennia", UNITS, DTK_MILLENNIUM},
00216 {DMILLENNIUM, UNITS, DTK_MILLENNIUM},
00217 {"millisecon", UNITS, DTK_MILLISEC},
00218 {"mils", UNITS, DTK_MILLENNIUM},
00219 {"min", UNITS, DTK_MINUTE},
00220 {"mins", UNITS, DTK_MINUTE},
00221 {DMINUTE, UNITS, DTK_MINUTE},
00222 {"minutes", UNITS, DTK_MINUTE},
00223 {"mon", UNITS, DTK_MONTH},
00224 {"mons", UNITS, DTK_MONTH},
00225 {DMONTH, UNITS, DTK_MONTH},
00226 {"months", UNITS, DTK_MONTH},
00227 {"ms", UNITS, DTK_MILLISEC},
00228 {"msec", UNITS, DTK_MILLISEC},
00229 {DMILLISEC, UNITS, DTK_MILLISEC},
00230 {"mseconds", UNITS, DTK_MILLISEC},
00231 {"msecs", UNITS, DTK_MILLISEC},
00232 {"qtr", UNITS, DTK_QUARTER},
00233 {DQUARTER, UNITS, DTK_QUARTER},
00234 {"s", UNITS, DTK_SECOND},
00235 {"sec", UNITS, DTK_SECOND},
00236 {DSECOND, UNITS, DTK_SECOND},
00237 {"seconds", UNITS, DTK_SECOND},
00238 {"secs", UNITS, DTK_SECOND},
00239 {DTIMEZONE, UNITS, DTK_TZ},
00240 {"timezone_h", UNITS, DTK_TZ_HOUR},
00241 {"timezone_m", UNITS, DTK_TZ_MINUTE},
00242 {"undefined", RESERV, DTK_INVALID},
00243 {"us", UNITS, DTK_MICROSEC},
00244 {"usec", UNITS, DTK_MICROSEC},
00245 {DMICROSEC, UNITS, DTK_MICROSEC},
00246 {"useconds", UNITS, DTK_MICROSEC},
00247 {"usecs", UNITS, DTK_MICROSEC},
00248 {"w", UNITS, DTK_WEEK},
00249 {DWEEK, UNITS, DTK_WEEK},
00250 {"weeks", UNITS, DTK_WEEK},
00251 {"y", UNITS, DTK_YEAR},
00252 {DYEAR, UNITS, DTK_YEAR},
00253 {"years", UNITS, DTK_YEAR},
00254 {"yr", UNITS, DTK_YEAR},
00255 {"yrs", UNITS, DTK_YEAR}
00256 };
00257
00258 static int szdeltatktbl = sizeof deltatktbl / sizeof deltatktbl[0];
00259
00260 static const datetkn *datecache[MAXDATEFIELDS] = {NULL};
00261
00262 static const datetkn *deltacache[MAXDATEFIELDS] = {NULL};
00263
00264
00265
00266
00267
00268 static int
00269 strtoi(const char *nptr, char **endptr, int base)
00270 {
00271 long val;
00272
00273 val = strtol(nptr, endptr, base);
00274 #ifdef HAVE_LONG_INT_64
00275 if (val != (long) ((int32) val))
00276 errno = ERANGE;
00277 #endif
00278 return (int) val;
00279 }
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300 int
00301 date2j(int y, int m, int d)
00302 {
00303 int julian;
00304 int century;
00305
00306 if (m > 2)
00307 {
00308 m += 1;
00309 y += 4800;
00310 }
00311 else
00312 {
00313 m += 13;
00314 y += 4799;
00315 }
00316
00317 century = y / 100;
00318 julian = y * 365 - 32167;
00319 julian += y / 4 - century + century / 4;
00320 julian += 7834 * m / 256 + d;
00321
00322 return julian;
00323 }
00324
00325 void
00326 j2date(int jd, int *year, int *month, int *day)
00327 {
00328 unsigned int julian;
00329 unsigned int quad;
00330 unsigned int extra;
00331 int y;
00332
00333 julian = jd;
00334 julian += 32044;
00335 quad = julian / 146097;
00336 extra = (julian - quad * 146097) * 4 + 3;
00337 julian += 60 + quad * 3 + extra / 146097;
00338 quad = julian / 1461;
00339 julian -= quad * 1461;
00340 y = julian * 4 / 1461;
00341 julian = ((y != 0) ? ((julian + 305) % 365) : ((julian + 306) % 366))
00342 + 123;
00343 y += quad * 4;
00344 *year = y - 4800;
00345 quad = julian * 2141 / 65536;
00346 *day = julian - 7834 * quad / 256;
00347 *month = (quad + 10) % MONTHS_PER_YEAR + 1;
00348
00349 return;
00350 }
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360 int
00361 j2day(int date)
00362 {
00363 unsigned int day;
00364
00365 day = date;
00366
00367 day += 1;
00368 day %= 7;
00369
00370 return (int) day;
00371 }
00372
00373
00374
00375
00376
00377
00378
00379 void
00380 GetCurrentDateTime(struct pg_tm * tm)
00381 {
00382 int tz;
00383 fsec_t fsec;
00384
00385 timestamp2tm(GetCurrentTransactionStartTimestamp(), &tz, tm, &fsec,
00386 NULL, NULL);
00387
00388 }
00389
00390
00391
00392
00393
00394
00395
00396 void
00397 GetCurrentTimeUsec(struct pg_tm * tm, fsec_t *fsec, int *tzp)
00398 {
00399 int tz;
00400
00401 timestamp2tm(GetCurrentTransactionStartTimestamp(), &tz, tm, fsec,
00402 NULL, NULL);
00403
00404 if (tzp != NULL)
00405 *tzp = tz;
00406 }
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416 static void
00417 TrimTrailingZeros(char *str)
00418 {
00419 int len = strlen(str);
00420
00421 while (len > 1 && *(str + len - 1) == '0' && *(str + len - 2) != '.')
00422 {
00423 len--;
00424 *(str + len) = '\0';
00425 }
00426 }
00427
00428
00429
00430
00431
00432
00433
00434 static void
00435 AppendSeconds(char *cp, int sec, fsec_t fsec, int precision, bool fillzeros)
00436 {
00437 if (fsec == 0)
00438 {
00439 if (fillzeros)
00440 sprintf(cp, "%02d", abs(sec));
00441 else
00442 sprintf(cp, "%d", abs(sec));
00443 }
00444 else
00445 {
00446 #ifdef HAVE_INT64_TIMESTAMP
00447 if (fillzeros)
00448 sprintf(cp, "%02d.%0*d", abs(sec), precision, (int) Abs(fsec));
00449 else
00450 sprintf(cp, "%d.%0*d", abs(sec), precision, (int) Abs(fsec));
00451 #else
00452 if (fillzeros)
00453 sprintf(cp, "%0*.*f", precision + 3, precision, fabs(sec + fsec));
00454 else
00455 sprintf(cp, "%.*f", precision, fabs(sec + fsec));
00456 #endif
00457 TrimTrailingZeros(cp);
00458 }
00459 }
00460
00461
00462 static void
00463 AppendTimestampSeconds(char *cp, struct pg_tm * tm, fsec_t fsec)
00464 {
00465
00466
00467
00468
00469 #ifndef HAVE_INT64_TIMESTAMP
00470 if (tm->tm_year <= 0)
00471 fsec = 0;
00472 #endif
00473 AppendSeconds(cp, tm->tm_sec, fsec, MAX_TIMESTAMP_PRECISION, true);
00474 }
00475
00476
00477
00478
00479
00480 static void
00481 AdjustFractSeconds(double frac, struct pg_tm * tm, fsec_t *fsec, int scale)
00482 {
00483 int sec;
00484
00485 if (frac == 0)
00486 return;
00487 frac *= scale;
00488 sec = (int) frac;
00489 tm->tm_sec += sec;
00490 frac -= sec;
00491 #ifdef HAVE_INT64_TIMESTAMP
00492 *fsec += rint(frac * 1000000);
00493 #else
00494 *fsec += frac;
00495 #endif
00496 }
00497
00498
00499 static void
00500 AdjustFractDays(double frac, struct pg_tm * tm, fsec_t *fsec, int scale)
00501 {
00502 int extra_days;
00503
00504 if (frac == 0)
00505 return;
00506 frac *= scale;
00507 extra_days = (int) frac;
00508 tm->tm_mday += extra_days;
00509 frac -= extra_days;
00510 AdjustFractSeconds(frac, tm, fsec, SECS_PER_DAY);
00511 }
00512
00513
00514 static int
00515 ParseFractionalSecond(char *cp, fsec_t *fsec)
00516 {
00517 double frac;
00518
00519
00520 Assert(*cp == '.');
00521 errno = 0;
00522 frac = strtod(cp, &cp);
00523
00524 if (*cp != '\0' || errno != 0)
00525 return DTERR_BAD_FORMAT;
00526 #ifdef HAVE_INT64_TIMESTAMP
00527 *fsec = rint(frac * 1000000);
00528 #else
00529 *fsec = frac;
00530 #endif
00531 return 0;
00532 }
00533
00534
00535
00536
00537
00538
00539
00540
00541
00542
00543
00544
00545
00546
00547
00548
00549
00550
00551
00552
00553
00554
00555
00556
00557
00558
00559
00560
00561
00562
00563
00564
00565
00566 int
00567 ParseDateTime(const char *timestr, char *workbuf, size_t buflen,
00568 char **field, int *ftype, int maxfields, int *numfields)
00569 {
00570 int nf = 0;
00571 const char *cp = timestr;
00572 char *bufp = workbuf;
00573 const char *bufend = workbuf + buflen;
00574
00575
00576
00577
00578
00579
00580
00581 #define APPEND_CHAR(bufptr, end, newchar) \
00582 do \
00583 { \
00584 if (((bufptr) + 1) >= (end)) \
00585 return DTERR_BAD_FORMAT; \
00586 *(bufptr)++ = newchar; \
00587 } while (0)
00588
00589
00590 while (*cp != '\0')
00591 {
00592
00593 if (isspace((unsigned char) *cp))
00594 {
00595 cp++;
00596 continue;
00597 }
00598
00599
00600 if (nf >= maxfields)
00601 return DTERR_BAD_FORMAT;
00602 field[nf] = bufp;
00603
00604
00605 if (isdigit((unsigned char) *cp))
00606 {
00607 APPEND_CHAR(bufp, bufend, *cp++);
00608 while (isdigit((unsigned char) *cp))
00609 APPEND_CHAR(bufp, bufend, *cp++);
00610
00611
00612 if (*cp == ':')
00613 {
00614 ftype[nf] = DTK_TIME;
00615 APPEND_CHAR(bufp, bufend, *cp++);
00616 while (isdigit((unsigned char) *cp) ||
00617 (*cp == ':') || (*cp == '.'))
00618 APPEND_CHAR(bufp, bufend, *cp++);
00619 }
00620
00621 else if (*cp == '-' || *cp == '/' || *cp == '.')
00622 {
00623
00624 char delim = *cp;
00625
00626 APPEND_CHAR(bufp, bufend, *cp++);
00627
00628 if (isdigit((unsigned char) *cp))
00629 {
00630 ftype[nf] = ((delim == '.') ? DTK_NUMBER : DTK_DATE);
00631 while (isdigit((unsigned char) *cp))
00632 APPEND_CHAR(bufp, bufend, *cp++);
00633
00634
00635
00636
00637
00638 if (*cp == delim)
00639 {
00640 ftype[nf] = DTK_DATE;
00641 APPEND_CHAR(bufp, bufend, *cp++);
00642 while (isdigit((unsigned char) *cp) || *cp == delim)
00643 APPEND_CHAR(bufp, bufend, *cp++);
00644 }
00645 }
00646 else
00647 {
00648 ftype[nf] = DTK_DATE;
00649 while (isalnum((unsigned char) *cp) || *cp == delim)
00650 APPEND_CHAR(bufp, bufend, pg_tolower((unsigned char) *cp++));
00651 }
00652 }
00653
00654
00655
00656
00657
00658 else
00659 ftype[nf] = DTK_NUMBER;
00660 }
00661
00662 else if (*cp == '.')
00663 {
00664 APPEND_CHAR(bufp, bufend, *cp++);
00665 while (isdigit((unsigned char) *cp))
00666 APPEND_CHAR(bufp, bufend, *cp++);
00667
00668 ftype[nf] = DTK_NUMBER;
00669 }
00670
00671
00672
00673
00674 else if (isalpha((unsigned char) *cp))
00675 {
00676 bool is_date;
00677
00678 ftype[nf] = DTK_STRING;
00679 APPEND_CHAR(bufp, bufend, pg_tolower((unsigned char) *cp++));
00680 while (isalpha((unsigned char) *cp))
00681 APPEND_CHAR(bufp, bufend, pg_tolower((unsigned char) *cp++));
00682
00683
00684
00685
00686
00687
00688
00689
00690
00691 is_date = false;
00692 if (*cp == '-' || *cp == '/' || *cp == '.')
00693 is_date = true;
00694 else if (*cp == '+' || isdigit((unsigned char) *cp))
00695 {
00696 *bufp = '\0';
00697
00698 if (datebsearch(field[nf], datetktbl, szdatetktbl) == NULL)
00699 is_date = true;
00700 }
00701 if (is_date)
00702 {
00703 ftype[nf] = DTK_DATE;
00704 do
00705 {
00706 APPEND_CHAR(bufp, bufend, pg_tolower((unsigned char) *cp++));
00707 } while (*cp == '+' || *cp == '-' ||
00708 *cp == '/' || *cp == '_' ||
00709 *cp == '.' || *cp == ':' ||
00710 isalnum((unsigned char) *cp));
00711 }
00712 }
00713
00714 else if (*cp == '+' || *cp == '-')
00715 {
00716 APPEND_CHAR(bufp, bufend, *cp++);
00717
00718 while (isspace((unsigned char) *cp))
00719 cp++;
00720
00721
00722 if (isdigit((unsigned char) *cp))
00723 {
00724 ftype[nf] = DTK_TZ;
00725 APPEND_CHAR(bufp, bufend, *cp++);
00726 while (isdigit((unsigned char) *cp) ||
00727 *cp == ':' || *cp == '.' || *cp == '-')
00728 APPEND_CHAR(bufp, bufend, *cp++);
00729 }
00730
00731 else if (isalpha((unsigned char) *cp))
00732 {
00733 ftype[nf] = DTK_SPECIAL;
00734 APPEND_CHAR(bufp, bufend, pg_tolower((unsigned char) *cp++));
00735 while (isalpha((unsigned char) *cp))
00736 APPEND_CHAR(bufp, bufend, pg_tolower((unsigned char) *cp++));
00737 }
00738
00739 else
00740 return DTERR_BAD_FORMAT;
00741 }
00742
00743 else if (ispunct((unsigned char) *cp))
00744 {
00745 cp++;
00746 continue;
00747 }
00748
00749 else
00750 return DTERR_BAD_FORMAT;
00751
00752
00753 *bufp++ = '\0';
00754 nf++;
00755 }
00756
00757 *numfields = nf;
00758
00759 return 0;
00760 }
00761
00762
00763
00764
00765
00766
00767
00768
00769
00770
00771
00772
00773
00774
00775
00776
00777
00778
00779
00780
00781
00782
00783
00784
00785
00786
00787 int
00788 DecodeDateTime(char **field, int *ftype, int nf,
00789 int *dtype, struct pg_tm * tm, fsec_t *fsec, int *tzp)
00790 {
00791 int fmask = 0,
00792 tmask,
00793 type;
00794 int ptype = 0;
00795 int i;
00796 int val;
00797 int dterr;
00798 int mer = HR24;
00799 bool haveTextMonth = FALSE;
00800 bool isjulian = FALSE;
00801 bool is2digits = FALSE;
00802 bool bc = FALSE;
00803 pg_tz *namedTz = NULL;
00804 struct pg_tm cur_tm;
00805
00806
00807
00808
00809
00810 *dtype = DTK_DATE;
00811 tm->tm_hour = 0;
00812 tm->tm_min = 0;
00813 tm->tm_sec = 0;
00814 *fsec = 0;
00815
00816 tm->tm_isdst = -1;
00817 if (tzp != NULL)
00818 *tzp = 0;
00819
00820 for (i = 0; i < nf; i++)
00821 {
00822 switch (ftype[i])
00823 {
00824 case DTK_DATE:
00825
00826
00827
00828
00829
00830 if (ptype == DTK_JULIAN)
00831 {
00832 char *cp;
00833 int val;
00834
00835 if (tzp == NULL)
00836 return DTERR_BAD_FORMAT;
00837
00838 errno = 0;
00839 val = strtoi(field[i], &cp, 10);
00840 if (errno == ERANGE || val < 0)
00841 return DTERR_FIELD_OVERFLOW;
00842
00843 j2date(val, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
00844 isjulian = TRUE;
00845
00846
00847 dterr = DecodeTimezone(cp, tzp);
00848 if (dterr)
00849 return dterr;
00850
00851 tmask = DTK_DATE_M | DTK_TIME_M | DTK_M(TZ);
00852 ptype = 0;
00853 break;
00854 }
00855
00856
00857
00858
00859
00860
00861
00862
00863
00864
00865 else if (ptype != 0 ||
00866 ((fmask & (DTK_M(MONTH) | DTK_M(DAY))) ==
00867 (DTK_M(MONTH) | DTK_M(DAY))))
00868 {
00869
00870 if (tzp == NULL)
00871 return DTERR_BAD_FORMAT;
00872
00873 if (isdigit((unsigned char) *field[i]) || ptype != 0)
00874 {
00875 char *cp;
00876
00877 if (ptype != 0)
00878 {
00879
00880 if (ptype != DTK_TIME)
00881 return DTERR_BAD_FORMAT;
00882 ptype = 0;
00883 }
00884
00885
00886
00887
00888
00889
00890 if ((fmask & DTK_TIME_M) == DTK_TIME_M)
00891 return DTERR_BAD_FORMAT;
00892
00893 if ((cp = strchr(field[i], '-')) == NULL)
00894 return DTERR_BAD_FORMAT;
00895
00896
00897 dterr = DecodeTimezone(cp, tzp);
00898 if (dterr)
00899 return dterr;
00900 *cp = '\0';
00901
00902
00903
00904
00905
00906 dterr = DecodeNumberField(strlen(field[i]), field[i],
00907 fmask,
00908 &tmask, tm,
00909 fsec, &is2digits);
00910 if (dterr < 0)
00911 return dterr;
00912
00913
00914
00915
00916
00917 tmask |= DTK_M(TZ);
00918 }
00919 else
00920 {
00921 namedTz = pg_tzset(field[i]);
00922 if (!namedTz)
00923 {
00924
00925
00926
00927
00928
00929 ereport(ERROR,
00930 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
00931 errmsg("time zone \"%s\" not recognized",
00932 field[i])));
00933 }
00934
00935 tmask = DTK_M(TZ);
00936 }
00937 }
00938 else
00939 {
00940 dterr = DecodeDate(field[i], fmask,
00941 &tmask, &is2digits, tm);
00942 if (dterr)
00943 return dterr;
00944 }
00945 break;
00946
00947 case DTK_TIME:
00948
00949
00950
00951 if (ptype != 0)
00952 {
00953
00954 if (ptype != DTK_TIME)
00955 return DTERR_BAD_FORMAT;
00956 ptype = 0;
00957 }
00958 dterr = DecodeTime(field[i], fmask, INTERVAL_FULL_RANGE,
00959 &tmask, tm, fsec);
00960 if (dterr)
00961 return dterr;
00962
00963
00964
00965
00966
00967
00968 if (tm->tm_hour > HOURS_PER_DAY ||
00969 (tm->tm_hour == HOURS_PER_DAY &&
00970 (tm->tm_min > 0 || tm->tm_sec > 0 || *fsec > 0)))
00971 return DTERR_FIELD_OVERFLOW;
00972 break;
00973
00974 case DTK_TZ:
00975 {
00976 int tz;
00977
00978 if (tzp == NULL)
00979 return DTERR_BAD_FORMAT;
00980
00981 dterr = DecodeTimezone(field[i], &tz);
00982 if (dterr)
00983 return dterr;
00984 *tzp = tz;
00985 tmask = DTK_M(TZ);
00986 }
00987 break;
00988
00989 case DTK_NUMBER:
00990
00991
00992
00993
00994
00995 if (ptype != 0)
00996 {
00997 char *cp;
00998 int val;
00999
01000 errno = 0;
01001 val = strtoi(field[i], &cp, 10);
01002 if (errno == ERANGE)
01003 return DTERR_FIELD_OVERFLOW;
01004
01005
01006
01007
01008
01009 if (*cp == '.')
01010 switch (ptype)
01011 {
01012 case DTK_JULIAN:
01013 case DTK_TIME:
01014 case DTK_SECOND:
01015 break;
01016 default:
01017 return DTERR_BAD_FORMAT;
01018 break;
01019 }
01020 else if (*cp != '\0')
01021 return DTERR_BAD_FORMAT;
01022
01023 switch (ptype)
01024 {
01025 case DTK_YEAR:
01026 tm->tm_year = val;
01027 tmask = DTK_M(YEAR);
01028 break;
01029
01030 case DTK_MONTH:
01031
01032
01033
01034
01035
01036 if ((fmask & DTK_M(MONTH)) != 0 &&
01037 (fmask & DTK_M(HOUR)) != 0)
01038 {
01039 tm->tm_min = val;
01040 tmask = DTK_M(MINUTE);
01041 }
01042 else
01043 {
01044 tm->tm_mon = val;
01045 tmask = DTK_M(MONTH);
01046 }
01047 break;
01048
01049 case DTK_DAY:
01050 tm->tm_mday = val;
01051 tmask = DTK_M(DAY);
01052 break;
01053
01054 case DTK_HOUR:
01055 tm->tm_hour = val;
01056 tmask = DTK_M(HOUR);
01057 break;
01058
01059 case DTK_MINUTE:
01060 tm->tm_min = val;
01061 tmask = DTK_M(MINUTE);
01062 break;
01063
01064 case DTK_SECOND:
01065 tm->tm_sec = val;
01066 tmask = DTK_M(SECOND);
01067 if (*cp == '.')
01068 {
01069 dterr = ParseFractionalSecond(cp, fsec);
01070 if (dterr)
01071 return dterr;
01072 tmask = DTK_ALL_SECS_M;
01073 }
01074 break;
01075
01076 case DTK_TZ:
01077 tmask = DTK_M(TZ);
01078 dterr = DecodeTimezone(field[i], tzp);
01079 if (dterr)
01080 return dterr;
01081 break;
01082
01083 case DTK_JULIAN:
01084
01085 if (val < 0)
01086 return DTERR_FIELD_OVERFLOW;
01087 tmask = DTK_DATE_M;
01088 j2date(val, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
01089 isjulian = TRUE;
01090
01091
01092 if (*cp == '.')
01093 {
01094 double time;
01095
01096 errno = 0;
01097 time = strtod(cp, &cp);
01098 if (*cp != '\0' || errno != 0)
01099 return DTERR_BAD_FORMAT;
01100
01101 #ifdef HAVE_INT64_TIMESTAMP
01102 time *= USECS_PER_DAY;
01103 #else
01104 time *= SECS_PER_DAY;
01105 #endif
01106 dt2time(time,
01107 &tm->tm_hour, &tm->tm_min,
01108 &tm->tm_sec, fsec);
01109 tmask |= DTK_TIME_M;
01110 }
01111 break;
01112
01113 case DTK_TIME:
01114
01115 dterr = DecodeNumberField(strlen(field[i]), field[i],
01116 (fmask | DTK_DATE_M),
01117 &tmask, tm,
01118 fsec, &is2digits);
01119 if (dterr < 0)
01120 return dterr;
01121 if (tmask != DTK_TIME_M)
01122 return DTERR_BAD_FORMAT;
01123 break;
01124
01125 default:
01126 return DTERR_BAD_FORMAT;
01127 break;
01128 }
01129
01130 ptype = 0;
01131 *dtype = DTK_DATE;
01132 }
01133 else
01134 {
01135 char *cp;
01136 int flen;
01137
01138 flen = strlen(field[i]);
01139 cp = strchr(field[i], '.');
01140
01141
01142 if (cp != NULL && !(fmask & DTK_DATE_M))
01143 {
01144 dterr = DecodeDate(field[i], fmask,
01145 &tmask, &is2digits, tm);
01146 if (dterr)
01147 return dterr;
01148 }
01149
01150 else if (cp != NULL && flen - strlen(cp) > 2)
01151 {
01152
01153
01154
01155
01156
01157 dterr = DecodeNumberField(flen, field[i], fmask,
01158 &tmask, tm,
01159 fsec, &is2digits);
01160 if (dterr < 0)
01161 return dterr;
01162 }
01163 else if (flen > 4)
01164 {
01165 dterr = DecodeNumberField(flen, field[i], fmask,
01166 &tmask, tm,
01167 fsec, &is2digits);
01168 if (dterr < 0)
01169 return dterr;
01170 }
01171
01172 else
01173 {
01174 dterr = DecodeNumber(flen, field[i],
01175 haveTextMonth, fmask,
01176 &tmask, tm,
01177 fsec, &is2digits);
01178 if (dterr)
01179 return dterr;
01180 }
01181 }
01182 break;
01183
01184 case DTK_STRING:
01185 case DTK_SPECIAL:
01186 type = DecodeSpecial(i, field[i], &val);
01187 if (type == IGNORE_DTF)
01188 continue;
01189
01190 tmask = DTK_M(type);
01191 switch (type)
01192 {
01193 case RESERV:
01194 switch (val)
01195 {
01196 case DTK_CURRENT:
01197 ereport(ERROR,
01198 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
01199 errmsg("date/time value \"current\" is no longer supported")));
01200
01201 return DTERR_BAD_FORMAT;
01202 break;
01203
01204 case DTK_NOW:
01205 tmask = (DTK_DATE_M | DTK_TIME_M | DTK_M(TZ));
01206 *dtype = DTK_DATE;
01207 GetCurrentTimeUsec(tm, fsec, tzp);
01208 break;
01209
01210 case DTK_YESTERDAY:
01211 tmask = DTK_DATE_M;
01212 *dtype = DTK_DATE;
01213 GetCurrentDateTime(&cur_tm);
01214 j2date(date2j(cur_tm.tm_year, cur_tm.tm_mon, cur_tm.tm_mday) - 1,
01215 &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
01216 break;
01217
01218 case DTK_TODAY:
01219 tmask = DTK_DATE_M;
01220 *dtype = DTK_DATE;
01221 GetCurrentDateTime(&cur_tm);
01222 tm->tm_year = cur_tm.tm_year;
01223 tm->tm_mon = cur_tm.tm_mon;
01224 tm->tm_mday = cur_tm.tm_mday;
01225 break;
01226
01227 case DTK_TOMORROW:
01228 tmask = DTK_DATE_M;
01229 *dtype = DTK_DATE;
01230 GetCurrentDateTime(&cur_tm);
01231 j2date(date2j(cur_tm.tm_year, cur_tm.tm_mon, cur_tm.tm_mday) + 1,
01232 &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
01233 break;
01234
01235 case DTK_ZULU:
01236 tmask = (DTK_TIME_M | DTK_M(TZ));
01237 *dtype = DTK_DATE;
01238 tm->tm_hour = 0;
01239 tm->tm_min = 0;
01240 tm->tm_sec = 0;
01241 if (tzp != NULL)
01242 *tzp = 0;
01243 break;
01244
01245 default:
01246 *dtype = val;
01247 }
01248
01249 break;
01250
01251 case MONTH:
01252
01253
01254
01255
01256
01257 if ((fmask & DTK_M(MONTH)) && !haveTextMonth &&
01258 !(fmask & DTK_M(DAY)) && tm->tm_mon >= 1 &&
01259 tm->tm_mon <= 31)
01260 {
01261 tm->tm_mday = tm->tm_mon;
01262 tmask = DTK_M(DAY);
01263 }
01264 haveTextMonth = TRUE;
01265 tm->tm_mon = val;
01266 break;
01267
01268 case DTZMOD:
01269
01270
01271
01272
01273
01274 tmask |= DTK_M(DTZ);
01275 tm->tm_isdst = 1;
01276 if (tzp == NULL)
01277 return DTERR_BAD_FORMAT;
01278 *tzp += val * MINS_PER_HOUR;
01279 break;
01280
01281 case DTZ:
01282
01283
01284
01285
01286
01287 tmask |= DTK_M(TZ);
01288 tm->tm_isdst = 1;
01289 if (tzp == NULL)
01290 return DTERR_BAD_FORMAT;
01291 *tzp = val * MINS_PER_HOUR;
01292 break;
01293
01294 case TZ:
01295 tm->tm_isdst = 0;
01296 if (tzp == NULL)
01297 return DTERR_BAD_FORMAT;
01298 *tzp = val * MINS_PER_HOUR;
01299 break;
01300
01301 case IGNORE_DTF:
01302 break;
01303
01304 case AMPM:
01305 mer = val;
01306 break;
01307
01308 case ADBC:
01309 bc = (val == BC);
01310 break;
01311
01312 case DOW:
01313 tm->tm_wday = val;
01314 break;
01315
01316 case UNITS:
01317 tmask = 0;
01318 ptype = val;
01319 break;
01320
01321 case ISOTIME:
01322
01323
01324
01325
01326
01327 tmask = 0;
01328
01329
01330 if ((fmask & DTK_DATE_M) != DTK_DATE_M)
01331 return DTERR_BAD_FORMAT;
01332
01333
01334
01335
01336
01337
01338
01339 if (i >= nf - 1 ||
01340 (ftype[i + 1] != DTK_NUMBER &&
01341 ftype[i + 1] != DTK_TIME &&
01342 ftype[i + 1] != DTK_DATE))
01343 return DTERR_BAD_FORMAT;
01344
01345 ptype = val;
01346 break;
01347
01348 case UNKNOWN_FIELD:
01349
01350
01351
01352
01353
01354 namedTz = pg_tzset(field[i]);
01355 if (!namedTz)
01356 return DTERR_BAD_FORMAT;
01357
01358 tmask = DTK_M(TZ);
01359 break;
01360
01361 default:
01362 return DTERR_BAD_FORMAT;
01363 }
01364 break;
01365
01366 default:
01367 return DTERR_BAD_FORMAT;
01368 }
01369
01370 if (tmask & fmask)
01371 return DTERR_BAD_FORMAT;
01372 fmask |= tmask;
01373 }
01374
01375
01376 dterr = ValidateDate(fmask, isjulian, is2digits, bc, tm);
01377 if (dterr)
01378 return dterr;
01379
01380
01381 if (mer != HR24 && tm->tm_hour > HOURS_PER_DAY / 2)
01382 return DTERR_FIELD_OVERFLOW;
01383 if (mer == AM && tm->tm_hour == HOURS_PER_DAY / 2)
01384 tm->tm_hour = 0;
01385 else if (mer == PM && tm->tm_hour != HOURS_PER_DAY / 2)
01386 tm->tm_hour += HOURS_PER_DAY / 2;
01387
01388
01389 if (*dtype == DTK_DATE)
01390 {
01391 if ((fmask & DTK_DATE_M) != DTK_DATE_M)
01392 {
01393 if ((fmask & DTK_TIME_M) == DTK_TIME_M)
01394 return 1;
01395 return DTERR_BAD_FORMAT;
01396 }
01397
01398
01399
01400
01401
01402 if (namedTz != NULL)
01403 {
01404
01405 if (fmask & DTK_M(DTZMOD))
01406 return DTERR_BAD_FORMAT;
01407
01408 *tzp = DetermineTimeZoneOffset(tm, namedTz);
01409 }
01410
01411
01412 if (tzp != NULL && !(fmask & DTK_M(TZ)))
01413 {
01414
01415
01416
01417
01418 if (fmask & DTK_M(DTZMOD))
01419 return DTERR_BAD_FORMAT;
01420
01421 *tzp = DetermineTimeZoneOffset(tm, session_timezone);
01422 }
01423 }
01424
01425 return 0;
01426 }
01427
01428
01429
01430
01431
01432
01433
01434
01435
01436
01437
01438
01439
01440 int
01441 DetermineTimeZoneOffset(struct pg_tm * tm, pg_tz *tzp)
01442 {
01443 int date,
01444 sec;
01445 pg_time_t day,
01446 mytime,
01447 prevtime,
01448 boundary,
01449 beforetime,
01450 aftertime;
01451 long int before_gmtoff,
01452 after_gmtoff;
01453 int before_isdst,
01454 after_isdst;
01455 int res;
01456
01457 if (tzp == session_timezone && HasCTZSet)
01458 {
01459 tm->tm_isdst = 0;
01460 return CTimeZone;
01461 }
01462
01463
01464
01465
01466
01467
01468
01469 if (!IS_VALID_JULIAN(tm->tm_year, tm->tm_mon, tm->tm_mday))
01470 goto overflow;
01471 date = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - UNIX_EPOCH_JDATE;
01472
01473 day = ((pg_time_t) date) * SECS_PER_DAY;
01474 if (day / SECS_PER_DAY != date)
01475 goto overflow;
01476 sec = tm->tm_sec + (tm->tm_min + tm->tm_hour * MINS_PER_HOUR) * SECS_PER_MINUTE;
01477 mytime = day + sec;
01478
01479 if (mytime < 0 && day > 0)
01480 goto overflow;
01481
01482
01483
01484
01485
01486
01487
01488 prevtime = mytime - SECS_PER_DAY;
01489 if (mytime < 0 && prevtime > 0)
01490 goto overflow;
01491
01492 res = pg_next_dst_boundary(&prevtime,
01493 &before_gmtoff, &before_isdst,
01494 &boundary,
01495 &after_gmtoff, &after_isdst,
01496 tzp);
01497 if (res < 0)
01498 goto overflow;
01499
01500 if (res == 0)
01501 {
01502
01503 tm->tm_isdst = before_isdst;
01504 return -(int) before_gmtoff;
01505 }
01506
01507
01508
01509
01510 beforetime = mytime - before_gmtoff;
01511 if ((before_gmtoff > 0 &&
01512 mytime < 0 && beforetime > 0) ||
01513 (before_gmtoff <= 0 &&
01514 mytime > 0 && beforetime < 0))
01515 goto overflow;
01516 aftertime = mytime - after_gmtoff;
01517 if ((after_gmtoff > 0 &&
01518 mytime < 0 && aftertime > 0) ||
01519 (after_gmtoff <= 0 &&
01520 mytime > 0 && aftertime < 0))
01521 goto overflow;
01522
01523
01524
01525
01526 if (beforetime <= boundary && aftertime < boundary)
01527 {
01528 tm->tm_isdst = before_isdst;
01529 return -(int) before_gmtoff;
01530 }
01531 if (beforetime > boundary && aftertime >= boundary)
01532 {
01533 tm->tm_isdst = after_isdst;
01534 return -(int) after_gmtoff;
01535 }
01536
01537
01538
01539
01540
01541 if (after_isdst == 0)
01542 {
01543 tm->tm_isdst = after_isdst;
01544 return -(int) after_gmtoff;
01545 }
01546 tm->tm_isdst = before_isdst;
01547 return -(int) before_gmtoff;
01548
01549 overflow:
01550
01551 tm->tm_isdst = 0;
01552 return 0;
01553 }
01554
01555
01556
01557
01558
01559
01560
01561
01562
01563
01564
01565
01566
01567
01568 int
01569 DecodeTimeOnly(char **field, int *ftype, int nf,
01570 int *dtype, struct pg_tm * tm, fsec_t *fsec, int *tzp)
01571 {
01572 int fmask = 0,
01573 tmask,
01574 type;
01575 int ptype = 0;
01576 int i;
01577 int val;
01578 int dterr;
01579 bool isjulian = FALSE;
01580 bool is2digits = FALSE;
01581 bool bc = FALSE;
01582 int mer = HR24;
01583 pg_tz *namedTz = NULL;
01584
01585 *dtype = DTK_TIME;
01586 tm->tm_hour = 0;
01587 tm->tm_min = 0;
01588 tm->tm_sec = 0;
01589 *fsec = 0;
01590
01591 tm->tm_isdst = -1;
01592
01593 if (tzp != NULL)
01594 *tzp = 0;
01595
01596 for (i = 0; i < nf; i++)
01597 {
01598 switch (ftype[i])
01599 {
01600 case DTK_DATE:
01601
01602
01603
01604
01605
01606 if (tzp == NULL)
01607 return DTERR_BAD_FORMAT;
01608
01609
01610 if (i == 0 && nf >= 2 &&
01611 (ftype[nf - 1] == DTK_DATE || ftype[1] == DTK_TIME))
01612 {
01613 dterr = DecodeDate(field[i], fmask,
01614 &tmask, &is2digits, tm);
01615 if (dterr)
01616 return dterr;
01617 }
01618
01619 else
01620 {
01621 if (isdigit((unsigned char) *field[i]))
01622 {
01623 char *cp;
01624
01625
01626
01627
01628
01629 if ((fmask & DTK_TIME_M) == DTK_TIME_M)
01630 return DTERR_BAD_FORMAT;
01631
01632
01633
01634
01635 if ((cp = strchr(field[i], '-')) == NULL)
01636 return DTERR_BAD_FORMAT;
01637
01638
01639 dterr = DecodeTimezone(cp, tzp);
01640 if (dterr)
01641 return dterr;
01642 *cp = '\0';
01643
01644
01645
01646
01647
01648 dterr = DecodeNumberField(strlen(field[i]), field[i],
01649 (fmask | DTK_DATE_M),
01650 &tmask, tm,
01651 fsec, &is2digits);
01652 if (dterr < 0)
01653 return dterr;
01654 ftype[i] = dterr;
01655
01656 tmask |= DTK_M(TZ);
01657 }
01658 else
01659 {
01660 namedTz = pg_tzset(field[i]);
01661 if (!namedTz)
01662 {
01663
01664
01665
01666
01667
01668 ereport(ERROR,
01669 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
01670 errmsg("time zone \"%s\" not recognized",
01671 field[i])));
01672 }
01673
01674 ftype[i] = DTK_TZ;
01675 tmask = DTK_M(TZ);
01676 }
01677 }
01678 break;
01679
01680 case DTK_TIME:
01681 dterr = DecodeTime(field[i], (fmask | DTK_DATE_M),
01682 INTERVAL_FULL_RANGE,
01683 &tmask, tm, fsec);
01684 if (dterr)
01685 return dterr;
01686 break;
01687
01688 case DTK_TZ:
01689 {
01690 int tz;
01691
01692 if (tzp == NULL)
01693 return DTERR_BAD_FORMAT;
01694
01695 dterr = DecodeTimezone(field[i], &tz);
01696 if (dterr)
01697 return dterr;
01698 *tzp = tz;
01699 tmask = DTK_M(TZ);
01700 }
01701 break;
01702
01703 case DTK_NUMBER:
01704
01705
01706
01707
01708
01709 if (ptype != 0)
01710 {
01711 char *cp;
01712 int val;
01713
01714
01715 switch (ptype)
01716 {
01717 case DTK_JULIAN:
01718 case DTK_YEAR:
01719 case DTK_MONTH:
01720 case DTK_DAY:
01721 if (tzp == NULL)
01722 return DTERR_BAD_FORMAT;
01723 default:
01724 break;
01725 }
01726
01727 errno = 0;
01728 val = strtoi(field[i], &cp, 10);
01729 if (errno == ERANGE)
01730 return DTERR_FIELD_OVERFLOW;
01731
01732
01733
01734
01735
01736 if (*cp == '.')
01737 switch (ptype)
01738 {
01739 case DTK_JULIAN:
01740 case DTK_TIME:
01741 case DTK_SECOND:
01742 break;
01743 default:
01744 return DTERR_BAD_FORMAT;
01745 break;
01746 }
01747 else if (*cp != '\0')
01748 return DTERR_BAD_FORMAT;
01749
01750 switch (ptype)
01751 {
01752 case DTK_YEAR:
01753 tm->tm_year = val;
01754 tmask = DTK_M(YEAR);
01755 break;
01756
01757 case DTK_MONTH:
01758
01759
01760
01761
01762
01763 if ((fmask & DTK_M(MONTH)) != 0 &&
01764 (fmask & DTK_M(HOUR)) != 0)
01765 {
01766 tm->tm_min = val;
01767 tmask = DTK_M(MINUTE);
01768 }
01769 else
01770 {
01771 tm->tm_mon = val;
01772 tmask = DTK_M(MONTH);
01773 }
01774 break;
01775
01776 case DTK_DAY:
01777 tm->tm_mday = val;
01778 tmask = DTK_M(DAY);
01779 break;
01780
01781 case DTK_HOUR:
01782 tm->tm_hour = val;
01783 tmask = DTK_M(HOUR);
01784 break;
01785
01786 case DTK_MINUTE:
01787 tm->tm_min = val;
01788 tmask = DTK_M(MINUTE);
01789 break;
01790
01791 case DTK_SECOND:
01792 tm->tm_sec = val;
01793 tmask = DTK_M(SECOND);
01794 if (*cp == '.')
01795 {
01796 dterr = ParseFractionalSecond(cp, fsec);
01797 if (dterr)
01798 return dterr;
01799 tmask = DTK_ALL_SECS_M;
01800 }
01801 break;
01802
01803 case DTK_TZ:
01804 tmask = DTK_M(TZ);
01805 dterr = DecodeTimezone(field[i], tzp);
01806 if (dterr)
01807 return dterr;
01808 break;
01809
01810 case DTK_JULIAN:
01811
01812 if (val < 0)
01813 return DTERR_FIELD_OVERFLOW;
01814 tmask = DTK_DATE_M;
01815 j2date(val, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
01816 isjulian = TRUE;
01817
01818 if (*cp == '.')
01819 {
01820 double time;
01821
01822 errno = 0;
01823 time = strtod(cp, &cp);
01824 if (*cp != '\0' || errno != 0)
01825 return DTERR_BAD_FORMAT;
01826
01827 #ifdef HAVE_INT64_TIMESTAMP
01828 time *= USECS_PER_DAY;
01829 #else
01830 time *= SECS_PER_DAY;
01831 #endif
01832 dt2time(time,
01833 &tm->tm_hour, &tm->tm_min,
01834 &tm->tm_sec, fsec);
01835 tmask |= DTK_TIME_M;
01836 }
01837 break;
01838
01839 case DTK_TIME:
01840
01841 dterr = DecodeNumberField(strlen(field[i]), field[i],
01842 (fmask | DTK_DATE_M),
01843 &tmask, tm,
01844 fsec, &is2digits);
01845 if (dterr < 0)
01846 return dterr;
01847 ftype[i] = dterr;
01848
01849 if (tmask != DTK_TIME_M)
01850 return DTERR_BAD_FORMAT;
01851 break;
01852
01853 default:
01854 return DTERR_BAD_FORMAT;
01855 break;
01856 }
01857
01858 ptype = 0;
01859 *dtype = DTK_DATE;
01860 }
01861 else
01862 {
01863 char *cp;
01864 int flen;
01865
01866 flen = strlen(field[i]);
01867 cp = strchr(field[i], '.');
01868
01869
01870 if (cp != NULL)
01871 {
01872
01873
01874
01875
01876 if (i == 0 && nf >= 2 && ftype[nf - 1] == DTK_DATE)
01877 {
01878 dterr = DecodeDate(field[i], fmask,
01879 &tmask, &is2digits, tm);
01880 if (dterr)
01881 return dterr;
01882 }
01883
01884 else if (flen - strlen(cp) > 2)
01885 {
01886
01887
01888
01889
01890
01891 dterr = DecodeNumberField(flen, field[i],
01892 (fmask | DTK_DATE_M),
01893 &tmask, tm,
01894 fsec, &is2digits);
01895 if (dterr < 0)
01896 return dterr;
01897 ftype[i] = dterr;
01898 }
01899 else
01900 return DTERR_BAD_FORMAT;
01901 }
01902 else if (flen > 4)
01903 {
01904 dterr = DecodeNumberField(flen, field[i],
01905 (fmask | DTK_DATE_M),
01906 &tmask, tm,
01907 fsec, &is2digits);
01908 if (dterr < 0)
01909 return dterr;
01910 ftype[i] = dterr;
01911 }
01912
01913 else
01914 {
01915 dterr = DecodeNumber(flen, field[i],
01916 FALSE,
01917 (fmask | DTK_DATE_M),
01918 &tmask, tm,
01919 fsec, &is2digits);
01920 if (dterr)
01921 return dterr;
01922 }
01923 }
01924 break;
01925
01926 case DTK_STRING:
01927 case DTK_SPECIAL:
01928 type = DecodeSpecial(i, field[i], &val);
01929 if (type == IGNORE_DTF)
01930 continue;
01931
01932 tmask = DTK_M(type);
01933 switch (type)
01934 {
01935 case RESERV:
01936 switch (val)
01937 {
01938 case DTK_CURRENT:
01939 ereport(ERROR,
01940 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
01941 errmsg("date/time value \"current\" is no longer supported")));
01942 return DTERR_BAD_FORMAT;
01943 break;
01944
01945 case DTK_NOW:
01946 tmask = DTK_TIME_M;
01947 *dtype = DTK_TIME;
01948 GetCurrentTimeUsec(tm, fsec, NULL);
01949 break;
01950
01951 case DTK_ZULU:
01952 tmask = (DTK_TIME_M | DTK_M(TZ));
01953 *dtype = DTK_TIME;
01954 tm->tm_hour = 0;
01955 tm->tm_min = 0;
01956 tm->tm_sec = 0;
01957 tm->tm_isdst = 0;
01958 break;
01959
01960 default:
01961 return DTERR_BAD_FORMAT;
01962 }
01963
01964 break;
01965
01966 case DTZMOD:
01967
01968
01969
01970
01971
01972 tmask |= DTK_M(DTZ);
01973 tm->tm_isdst = 1;
01974 if (tzp == NULL)
01975 return DTERR_BAD_FORMAT;
01976 *tzp += val * MINS_PER_HOUR;
01977 break;
01978
01979 case DTZ:
01980
01981
01982
01983
01984
01985 tmask |= DTK_M(TZ);
01986 tm->tm_isdst = 1;
01987 if (tzp == NULL)
01988 return DTERR_BAD_FORMAT;
01989 *tzp = val * MINS_PER_HOUR;
01990 ftype[i] = DTK_TZ;
01991 break;
01992
01993 case TZ:
01994 tm->tm_isdst = 0;
01995 if (tzp == NULL)
01996 return DTERR_BAD_FORMAT;
01997 *tzp = val * MINS_PER_HOUR;
01998 ftype[i] = DTK_TZ;
01999 break;
02000
02001 case IGNORE_DTF:
02002 break;
02003
02004 case AMPM:
02005 mer = val;
02006 break;
02007
02008 case ADBC:
02009 bc = (val == BC);
02010 break;
02011
02012 case UNITS:
02013 tmask = 0;
02014 ptype = val;
02015 break;
02016
02017 case ISOTIME:
02018 tmask = 0;
02019
02020
02021
02022
02023
02024
02025
02026 if (i >= nf - 1 ||
02027 (ftype[i + 1] != DTK_NUMBER &&
02028 ftype[i + 1] != DTK_TIME &&
02029 ftype[i + 1] != DTK_DATE))
02030 return DTERR_BAD_FORMAT;
02031
02032 ptype = val;
02033 break;
02034
02035 case UNKNOWN_FIELD:
02036
02037
02038
02039
02040
02041 namedTz = pg_tzset(field[i]);
02042 if (!namedTz)
02043 return DTERR_BAD_FORMAT;
02044
02045 tmask = DTK_M(TZ);
02046 break;
02047
02048 default:
02049 return DTERR_BAD_FORMAT;
02050 }
02051 break;
02052
02053 default:
02054 return DTERR_BAD_FORMAT;
02055 }
02056
02057 if (tmask & fmask)
02058 return DTERR_BAD_FORMAT;
02059 fmask |= tmask;
02060 }
02061
02062
02063 dterr = ValidateDate(fmask, isjulian, is2digits, bc, tm);
02064 if (dterr)
02065 return dterr;
02066
02067
02068 if (mer != HR24 && tm->tm_hour > HOURS_PER_DAY / 2)
02069 return DTERR_FIELD_OVERFLOW;
02070 if (mer == AM && tm->tm_hour == HOURS_PER_DAY / 2)
02071 tm->tm_hour = 0;
02072 else if (mer == PM && tm->tm_hour != HOURS_PER_DAY / 2)
02073 tm->tm_hour += HOURS_PER_DAY / 2;
02074
02075 if (tm->tm_hour < 0 || tm->tm_min < 0 || tm->tm_min > MINS_PER_HOUR - 1 ||
02076 tm->tm_sec < 0 || tm->tm_sec > SECS_PER_MINUTE ||
02077 tm->tm_hour > HOURS_PER_DAY ||
02078
02079 (tm->tm_hour == HOURS_PER_DAY &&
02080 (tm->tm_min > 0 || tm->tm_sec > 0 || *fsec > 0)) ||
02081 #ifdef HAVE_INT64_TIMESTAMP
02082 *fsec < INT64CONST(0) || *fsec > USECS_PER_SEC
02083 #else
02084 *fsec < 0 || *fsec > 1
02085 #endif
02086 )
02087 return DTERR_FIELD_OVERFLOW;
02088
02089 if ((fmask & DTK_TIME_M) != DTK_TIME_M)
02090 return DTERR_BAD_FORMAT;
02091
02092
02093
02094
02095
02096 if (namedTz != NULL)
02097 {
02098 long int gmtoff;
02099
02100
02101 if (fmask & DTK_M(DTZMOD))
02102 return DTERR_BAD_FORMAT;
02103
02104
02105 if (pg_get_timezone_offset(namedTz, &gmtoff))
02106 {
02107 *tzp = -(int) gmtoff;
02108 }
02109 else
02110 {
02111
02112 if ((fmask & DTK_DATE_M) != DTK_DATE_M)
02113 return DTERR_BAD_FORMAT;
02114 *tzp = DetermineTimeZoneOffset(tm, namedTz);
02115 }
02116 }
02117
02118
02119 if (tzp != NULL && !(fmask & DTK_M(TZ)))
02120 {
02121 struct pg_tm tt,
02122 *tmp = &tt;
02123
02124
02125
02126
02127 if (fmask & DTK_M(DTZMOD))
02128 return DTERR_BAD_FORMAT;
02129
02130 if ((fmask & DTK_DATE_M) == 0)
02131 GetCurrentDateTime(tmp);
02132 else
02133 {
02134 tmp->tm_year = tm->tm_year;
02135 tmp->tm_mon = tm->tm_mon;
02136 tmp->tm_mday = tm->tm_mday;
02137 }
02138 tmp->tm_hour = tm->tm_hour;
02139 tmp->tm_min = tm->tm_min;
02140 tmp->tm_sec = tm->tm_sec;
02141 *tzp = DetermineTimeZoneOffset(tmp, session_timezone);
02142 tm->tm_isdst = tmp->tm_isdst;
02143 }
02144
02145 return 0;
02146 }
02147
02148
02149
02150
02151
02152
02153
02154
02155
02156
02157
02158 static int
02159 DecodeDate(char *str, int fmask, int *tmask, bool *is2digits,
02160 struct pg_tm * tm)
02161 {
02162 fsec_t fsec;
02163 int nf = 0;
02164 int i,
02165 len;
02166 int dterr;
02167 bool haveTextMonth = FALSE;
02168 int type,
02169 val,
02170 dmask = 0;
02171 char *field[MAXDATEFIELDS];
02172
02173 *tmask = 0;
02174
02175
02176 while (*str != '\0' && nf < MAXDATEFIELDS)
02177 {
02178
02179 while (*str != '\0' && !isalnum((unsigned char) *str))
02180 str++;
02181
02182 if (*str == '\0')
02183 return DTERR_BAD_FORMAT;
02184
02185 field[nf] = str;
02186 if (isdigit((unsigned char) *str))
02187 {
02188 while (isdigit((unsigned char) *str))
02189 str++;
02190 }
02191 else if (isalpha((unsigned char) *str))
02192 {
02193 while (isalpha((unsigned char) *str))
02194 str++;
02195 }
02196
02197
02198 if (*str != '\0')
02199 *str++ = '\0';
02200 nf++;
02201 }
02202
02203
02204 for (i = 0; i < nf; i++)
02205 {
02206 if (isalpha((unsigned char) *field[i]))
02207 {
02208 type = DecodeSpecial(i, field[i], &val);
02209 if (type == IGNORE_DTF)
02210 continue;
02211
02212 dmask = DTK_M(type);
02213 switch (type)
02214 {
02215 case MONTH:
02216 tm->tm_mon = val;
02217 haveTextMonth = TRUE;
02218 break;
02219
02220 default:
02221 return DTERR_BAD_FORMAT;
02222 }
02223 if (fmask & dmask)
02224 return DTERR_BAD_FORMAT;
02225
02226 fmask |= dmask;
02227 *tmask |= dmask;
02228
02229
02230 field[i] = NULL;
02231 }
02232 }
02233
02234
02235 for (i = 0; i < nf; i++)
02236 {
02237 if (field[i] == NULL)
02238 continue;
02239
02240 if ((len = strlen(field[i])) <= 0)
02241 return DTERR_BAD_FORMAT;
02242
02243 dterr = DecodeNumber(len, field[i], haveTextMonth, fmask,
02244 &dmask, tm,
02245 &fsec, is2digits);
02246 if (dterr)
02247 return dterr;
02248
02249 if (fmask & dmask)
02250 return DTERR_BAD_FORMAT;
02251
02252 fmask |= dmask;
02253 *tmask |= dmask;
02254 }
02255
02256 if ((fmask & ~(DTK_M(DOY) | DTK_M(TZ))) != DTK_DATE_M)
02257 return DTERR_BAD_FORMAT;
02258
02259
02260
02261 return 0;
02262 }
02263
02264
02265
02266
02267
02268 static int
02269 ValidateDate(int fmask, bool isjulian, bool is2digits, bool bc,
02270 struct pg_tm * tm)
02271 {
02272 if (fmask & DTK_M(YEAR))
02273 {
02274 if (isjulian)
02275 {
02276
02277 }
02278 else if (bc)
02279 {
02280
02281 if (tm->tm_year <= 0)
02282 return DTERR_FIELD_OVERFLOW;
02283
02284 tm->tm_year = -(tm->tm_year - 1);
02285 }
02286 else if (is2digits)
02287 {
02288
02289 if (tm->tm_year < 0)
02290 return DTERR_FIELD_OVERFLOW;
02291 if (tm->tm_year < 70)
02292 tm->tm_year += 2000;
02293 else if (tm->tm_year < 100)
02294 tm->tm_year += 1900;
02295 }
02296 else
02297 {
02298
02299 if (tm->tm_year <= 0)
02300 return DTERR_FIELD_OVERFLOW;
02301 }
02302 }
02303
02304
02305 if (fmask & DTK_M(DOY))
02306 {
02307 j2date(date2j(tm->tm_year, 1, 1) + tm->tm_yday - 1,
02308 &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
02309 }
02310
02311
02312 if (fmask & DTK_M(MONTH))
02313 {
02314 if (tm->tm_mon < 1 || tm->tm_mon > MONTHS_PER_YEAR)
02315 return DTERR_MD_FIELD_OVERFLOW;
02316 }
02317
02318
02319 if (fmask & DTK_M(DAY))
02320 {
02321 if (tm->tm_mday < 1 || tm->tm_mday > 31)
02322 return DTERR_MD_FIELD_OVERFLOW;
02323 }
02324
02325 if ((fmask & DTK_DATE_M) == DTK_DATE_M)
02326 {
02327
02328
02329
02330
02331
02332 if (tm->tm_mday > day_tab[isleap(tm->tm_year)][tm->tm_mon - 1])
02333 return DTERR_FIELD_OVERFLOW;
02334 }
02335
02336 return 0;
02337 }
02338
02339
02340
02341
02342
02343
02344
02345
02346
02347 static int
02348 DecodeTime(char *str, int fmask, int range,
02349 int *tmask, struct pg_tm * tm, fsec_t *fsec)
02350 {
02351 char *cp;
02352 int dterr;
02353
02354 *tmask = DTK_TIME_M;
02355
02356 errno = 0;
02357 tm->tm_hour = strtoi(str, &cp, 10);
02358 if (errno == ERANGE)
02359 return DTERR_FIELD_OVERFLOW;
02360 if (*cp != ':')
02361 return DTERR_BAD_FORMAT;
02362 errno = 0;
02363 tm->tm_min = strtoi(cp + 1, &cp, 10);
02364 if (errno == ERANGE)
02365 return DTERR_FIELD_OVERFLOW;
02366 if (*cp == '\0')
02367 {
02368 tm->tm_sec = 0;
02369 *fsec = 0;
02370
02371 if (range == (INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND)))
02372 {
02373 tm->tm_sec = tm->tm_min;
02374 tm->tm_min = tm->tm_hour;
02375 tm->tm_hour = 0;
02376 }
02377 }
02378 else if (*cp == '.')
02379 {
02380
02381 dterr = ParseFractionalSecond(cp, fsec);
02382 if (dterr)
02383 return dterr;
02384 tm->tm_sec = tm->tm_min;
02385 tm->tm_min = tm->tm_hour;
02386 tm->tm_hour = 0;
02387 }
02388 else if (*cp == ':')
02389 {
02390 errno = 0;
02391 tm->tm_sec = strtoi(cp + 1, &cp, 10);
02392 if (errno == ERANGE)
02393 return DTERR_FIELD_OVERFLOW;
02394 if (*cp == '\0')
02395 *fsec = 0;
02396 else if (*cp == '.')
02397 {
02398 dterr = ParseFractionalSecond(cp, fsec);
02399 if (dterr)
02400 return dterr;
02401 }
02402 else
02403 return DTERR_BAD_FORMAT;
02404 }
02405 else
02406 return DTERR_BAD_FORMAT;
02407
02408
02409 #ifdef HAVE_INT64_TIMESTAMP
02410 if (tm->tm_hour < 0 || tm->tm_min < 0 || tm->tm_min > MINS_PER_HOUR - 1 ||
02411 tm->tm_sec < 0 || tm->tm_sec > SECS_PER_MINUTE ||
02412 *fsec < INT64CONST(0) ||
02413 *fsec > USECS_PER_SEC)
02414 return DTERR_FIELD_OVERFLOW;
02415 #else
02416 if (tm->tm_hour < 0 || tm->tm_min < 0 || tm->tm_min > MINS_PER_HOUR - 1 ||
02417 tm->tm_sec < 0 || tm->tm_sec > SECS_PER_MINUTE ||
02418 *fsec < 0 || *fsec > 1)
02419 return DTERR_FIELD_OVERFLOW;
02420 #endif
02421
02422 return 0;
02423 }
02424
02425
02426
02427
02428
02429
02430 static int
02431 DecodeNumber(int flen, char *str, bool haveTextMonth, int fmask,
02432 int *tmask, struct pg_tm * tm, fsec_t *fsec, bool *is2digits)
02433 {
02434 int val;
02435 char *cp;
02436 int dterr;
02437
02438 *tmask = 0;
02439
02440 errno = 0;
02441 val = strtoi(str, &cp, 10);
02442 if (errno == ERANGE)
02443 return DTERR_FIELD_OVERFLOW;
02444 if (cp == str)
02445 return DTERR_BAD_FORMAT;
02446
02447 if (*cp == '.')
02448 {
02449
02450
02451
02452
02453 if (cp - str > 2)
02454 {
02455 dterr = DecodeNumberField(flen, str,
02456 (fmask | DTK_DATE_M),
02457 tmask, tm,
02458 fsec, is2digits);
02459 if (dterr < 0)
02460 return dterr;
02461 return 0;
02462 }
02463
02464 dterr = ParseFractionalSecond(cp, fsec);
02465 if (dterr)
02466 return dterr;
02467 }
02468 else if (*cp != '\0')
02469 return DTERR_BAD_FORMAT;
02470
02471
02472 if (flen == 3 && (fmask & DTK_DATE_M) == DTK_M(YEAR) && val >= 1 &&
02473 val <= 366)
02474 {
02475 *tmask = (DTK_M(DOY) | DTK_M(MONTH) | DTK_M(DAY));
02476 tm->tm_yday = val;
02477
02478 return 0;
02479 }
02480
02481
02482 switch (fmask & DTK_DATE_M)
02483 {
02484 case 0:
02485
02486
02487
02488
02489
02490
02491
02492
02493 if (flen >= 3 || DateOrder == DATEORDER_YMD)
02494 {
02495 *tmask = DTK_M(YEAR);
02496 tm->tm_year = val;
02497 }
02498 else if (DateOrder == DATEORDER_DMY)
02499 {
02500 *tmask = DTK_M(DAY);
02501 tm->tm_mday = val;
02502 }
02503 else
02504 {
02505 *tmask = DTK_M(MONTH);
02506 tm->tm_mon = val;
02507 }
02508 break;
02509
02510 case (DTK_M(YEAR)):
02511
02512 *tmask = DTK_M(MONTH);
02513 tm->tm_mon = val;
02514 break;
02515
02516 case (DTK_M(MONTH)):
02517 if (haveTextMonth)
02518 {
02519
02520
02521
02522
02523
02524
02525
02526 if (flen >= 3 || DateOrder == DATEORDER_YMD)
02527 {
02528 *tmask = DTK_M(YEAR);
02529 tm->tm_year = val;
02530 }
02531 else
02532 {
02533 *tmask = DTK_M(DAY);
02534 tm->tm_mday = val;
02535 }
02536 }
02537 else
02538 {
02539
02540 *tmask = DTK_M(DAY);
02541 tm->tm_mday = val;
02542 }
02543 break;
02544
02545 case (DTK_M(YEAR) | DTK_M(MONTH)):
02546 if (haveTextMonth)
02547 {
02548
02549 if (flen >= 3 && *is2digits)
02550 {
02551
02552 *tmask = DTK_M(DAY);
02553 tm->tm_mday = tm->tm_year;
02554 tm->tm_year = val;
02555 *is2digits = FALSE;
02556 }
02557 else
02558 {
02559 *tmask = DTK_M(DAY);
02560 tm->tm_mday = val;
02561 }
02562 }
02563 else
02564 {
02565
02566 *tmask = DTK_M(DAY);
02567 tm->tm_mday = val;
02568 }
02569 break;
02570
02571 case (DTK_M(DAY)):
02572
02573 *tmask = DTK_M(MONTH);
02574 tm->tm_mon = val;
02575 break;
02576
02577 case (DTK_M(MONTH) | DTK_M(DAY)):
02578
02579 *tmask = DTK_M(YEAR);
02580 tm->tm_year = val;
02581 break;
02582
02583 case (DTK_M(YEAR) | DTK_M(MONTH) | DTK_M(DAY)):
02584
02585 dterr = DecodeNumberField(flen, str, fmask,
02586 tmask, tm,
02587 fsec, is2digits);
02588 if (dterr < 0)
02589 return dterr;
02590 return 0;
02591
02592 default:
02593
02594 return DTERR_BAD_FORMAT;
02595 }
02596
02597
02598
02599
02600
02601 if (*tmask == DTK_M(YEAR))
02602 *is2digits = (flen <= 2);
02603
02604 return 0;
02605 }
02606
02607
02608
02609
02610
02611
02612
02613
02614
02615 static int
02616 DecodeNumberField(int len, char *str, int fmask,
02617 int *tmask, struct pg_tm * tm, fsec_t *fsec, bool *is2digits)
02618 {
02619 char *cp;
02620
02621
02622
02623
02624
02625 if ((cp = strchr(str, '.')) != NULL)
02626 {
02627
02628
02629
02630
02631 double frac;
02632
02633 errno = 0;
02634 frac = strtod(cp, NULL);
02635 if (errno != 0)
02636 return DTERR_BAD_FORMAT;
02637 #ifdef HAVE_INT64_TIMESTAMP
02638 *fsec = rint(frac * 1000000);
02639 #else
02640 *fsec = frac;
02641 #endif
02642
02643 *cp = '\0';
02644 len = strlen(str);
02645 }
02646
02647 else if ((fmask & DTK_DATE_M) != DTK_DATE_M)
02648 {
02649
02650 if (len == 8)
02651 {
02652 *tmask = DTK_DATE_M;
02653
02654 tm->tm_mday = atoi(str + 6);
02655 *(str + 6) = '\0';
02656 tm->tm_mon = atoi(str + 4);
02657 *(str + 4) = '\0';
02658 tm->tm_year = atoi(str + 0);
02659
02660 return DTK_DATE;
02661 }
02662
02663 else if (len == 6)
02664 {
02665 *tmask = DTK_DATE_M;
02666 tm->tm_mday = atoi(str + 4);
02667 *(str + 4) = '\0';
02668 tm->tm_mon = atoi(str + 2);
02669 *(str + 2) = '\0';
02670 tm->tm_year = atoi(str + 0);
02671 *is2digits = TRUE;
02672
02673 return DTK_DATE;
02674 }
02675 }
02676
02677
02678 if ((fmask & DTK_TIME_M) != DTK_TIME_M)
02679 {
02680
02681 if (len == 6)
02682 {
02683 *tmask = DTK_TIME_M;
02684 tm->tm_sec = atoi(str + 4);
02685 *(str + 4) = '\0';
02686 tm->tm_min = atoi(str + 2);
02687 *(str + 2) = '\0';
02688 tm->tm_hour = atoi(str + 0);
02689
02690 return DTK_TIME;
02691 }
02692
02693 else if (len == 4)
02694 {
02695 *tmask = DTK_TIME_M;
02696 tm->tm_sec = 0;
02697 tm->tm_min = atoi(str + 2);
02698 *(str + 2) = '\0';
02699 tm->tm_hour = atoi(str + 0);
02700
02701 return DTK_TIME;
02702 }
02703 }
02704
02705 return DTERR_BAD_FORMAT;
02706 }
02707
02708
02709
02710
02711
02712
02713
02714
02715
02716 static int
02717 DecodeTimezone(char *str, int *tzp)
02718 {
02719 int tz;
02720 int hr,
02721 min,
02722 sec = 0;
02723 char *cp;
02724
02725
02726 if (*str != '+' && *str != '-')
02727 return DTERR_BAD_FORMAT;
02728
02729 errno = 0;
02730 hr = strtoi(str + 1, &cp, 10);
02731 if (errno == ERANGE)
02732 return DTERR_TZDISP_OVERFLOW;
02733
02734
02735 if (*cp == ':')
02736 {
02737 errno = 0;
02738 min = strtoi(cp + 1, &cp, 10);
02739 if (errno == ERANGE)
02740 return DTERR_TZDISP_OVERFLOW;
02741 if (*cp == ':')
02742 {
02743 errno = 0;
02744 sec = strtoi(cp + 1, &cp, 10);
02745 if (errno == ERANGE)
02746 return DTERR_TZDISP_OVERFLOW;
02747 }
02748 }
02749
02750 else if (*cp == '\0' && strlen(str) > 3)
02751 {
02752 min = hr % 100;
02753 hr = hr / 100;
02754
02755 }
02756 else
02757 min = 0;
02758
02759
02760 if (hr < 0 || hr > MAX_TZDISP_HOUR)
02761 return DTERR_TZDISP_OVERFLOW;
02762 if (min < 0 || min >= MINS_PER_HOUR)
02763 return DTERR_TZDISP_OVERFLOW;
02764 if (sec < 0 || sec >= SECS_PER_MINUTE)
02765 return DTERR_TZDISP_OVERFLOW;
02766
02767 tz = (hr * MINS_PER_HOUR + min) * SECS_PER_MINUTE + sec;
02768 if (*str == '-')
02769 tz = -tz;
02770
02771 *tzp = -tz;
02772
02773 if (*cp != '\0')
02774 return DTERR_BAD_FORMAT;
02775
02776 return 0;
02777 }
02778
02779
02780
02781
02782
02783
02784
02785
02786
02787
02788 int
02789 DecodeSpecial(int field, char *lowtoken, int *val)
02790 {
02791 int type;
02792 const datetkn *tp;
02793
02794 tp = datecache[field];
02795 if (tp == NULL || strncmp(lowtoken, tp->token, TOKMAXLEN) != 0)
02796 {
02797 tp = datebsearch(lowtoken, timezonetktbl, sztimezonetktbl);
02798 if (tp == NULL)
02799 tp = datebsearch(lowtoken, datetktbl, szdatetktbl);
02800 }
02801 if (tp == NULL)
02802 {
02803 type = UNKNOWN_FIELD;
02804 *val = 0;
02805 }
02806 else
02807 {
02808 datecache[field] = tp;
02809 type = tp->type;
02810 switch (type)
02811 {
02812 case TZ:
02813 case DTZ:
02814 case DTZMOD:
02815 *val = FROMVAL(tp);
02816 break;
02817
02818 default:
02819 *val = tp->value;
02820 break;
02821 }
02822 }
02823
02824 return type;
02825 }
02826
02827
02828
02829
02830
02831
02832 static inline void
02833 ClearPgTm(struct pg_tm * tm, fsec_t *fsec)
02834 {
02835 tm->tm_year = 0;
02836 tm->tm_mon = 0;
02837 tm->tm_mday = 0;
02838 tm->tm_hour = 0;
02839 tm->tm_min = 0;
02840 tm->tm_sec = 0;
02841 *fsec = 0;
02842 }
02843
02844
02845
02846
02847
02848
02849
02850
02851
02852
02853
02854
02855
02856 int
02857 DecodeInterval(char **field, int *ftype, int nf, int range,
02858 int *dtype, struct pg_tm * tm, fsec_t *fsec)
02859 {
02860 bool is_before = FALSE;
02861 char *cp;
02862 int fmask = 0,
02863 tmask,
02864 type;
02865 int i;
02866 int dterr;
02867 int val;
02868 double fval;
02869
02870 *dtype = DTK_DELTA;
02871 type = IGNORE_DTF;
02872 ClearPgTm(tm, fsec);
02873
02874
02875 for (i = nf - 1; i >= 0; i--)
02876 {
02877 switch (ftype[i])
02878 {
02879 case DTK_TIME:
02880 dterr = DecodeTime(field[i], fmask, range,
02881 &tmask, tm, fsec);
02882 if (dterr)
02883 return dterr;
02884 type = DTK_DAY;
02885 break;
02886
02887 case DTK_TZ:
02888
02889
02890
02891
02892
02893
02894 Assert(*field[i] == '-' || *field[i] == '+');
02895
02896
02897
02898
02899
02900 if (strchr(field[i] + 1, ':') != NULL &&
02901 DecodeTime(field[i] + 1, fmask, range,
02902 &tmask, tm, fsec) == 0)
02903 {
02904 if (*field[i] == '-')
02905 {
02906
02907 tm->tm_hour = -tm->tm_hour;
02908 tm->tm_min = -tm->tm_min;
02909 tm->tm_sec = -tm->tm_sec;
02910 *fsec = -(*fsec);
02911 }
02912
02913
02914
02915
02916
02917
02918 type = DTK_DAY;
02919 break;
02920 }
02921
02922
02923
02924
02925
02926
02927
02928
02929 case DTK_DATE:
02930 case DTK_NUMBER:
02931 if (type == IGNORE_DTF)
02932 {
02933
02934 switch (range)
02935 {
02936 case INTERVAL_MASK(YEAR):
02937 type = DTK_YEAR;
02938 break;
02939 case INTERVAL_MASK(MONTH):
02940 case INTERVAL_MASK(YEAR) | INTERVAL_MASK(MONTH):
02941 type = DTK_MONTH;
02942 break;
02943 case INTERVAL_MASK(DAY):
02944 type = DTK_DAY;
02945 break;
02946 case INTERVAL_MASK(HOUR):
02947 case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR):
02948 type = DTK_HOUR;
02949 break;
02950 case INTERVAL_MASK(MINUTE):
02951 case INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE):
02952 case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE):
02953 type = DTK_MINUTE;
02954 break;
02955 case INTERVAL_MASK(SECOND):
02956 case INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND):
02957 case INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND):
02958 case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND):
02959 type = DTK_SECOND;
02960 break;
02961 default:
02962 type = DTK_SECOND;
02963 break;
02964 }
02965 }
02966
02967 errno = 0;
02968 val = strtoi(field[i], &cp, 10);
02969 if (errno == ERANGE)
02970 return DTERR_FIELD_OVERFLOW;
02971
02972 if (*cp == '-')
02973 {
02974
02975 int val2;
02976
02977 val2 = strtoi(cp + 1, &cp, 10);
02978 if (errno == ERANGE || val2 < 0 || val2 >= MONTHS_PER_YEAR)
02979 return DTERR_FIELD_OVERFLOW;
02980 if (*cp != '\0')
02981 return DTERR_BAD_FORMAT;
02982 type = DTK_MONTH;
02983 if (*field[i] == '-')
02984 val2 = -val2;
02985 val = val * MONTHS_PER_YEAR + val2;
02986 fval = 0;
02987 }
02988 else if (*cp == '.')
02989 {
02990 errno = 0;
02991 fval = strtod(cp, &cp);
02992 if (*cp != '\0' || errno != 0)
02993 return DTERR_BAD_FORMAT;
02994
02995 if (*field[i] == '-')
02996 fval = -fval;
02997 }
02998 else if (*cp == '\0')
02999 fval = 0;
03000 else
03001 return DTERR_BAD_FORMAT;
03002
03003 tmask = 0;
03004
03005 switch (type)
03006 {
03007 case DTK_MICROSEC:
03008 #ifdef HAVE_INT64_TIMESTAMP
03009 *fsec += rint(val + fval);
03010 #else
03011 *fsec += (val + fval) * 1e-6;
03012 #endif
03013 tmask = DTK_M(MICROSECOND);
03014 break;
03015
03016 case DTK_MILLISEC:
03017
03018 tm->tm_sec += val / 1000;
03019 val -= (val / 1000) * 1000;
03020 #ifdef HAVE_INT64_TIMESTAMP
03021 *fsec += rint((val + fval) * 1000);
03022 #else
03023 *fsec += (val + fval) * 1e-3;
03024 #endif
03025 tmask = DTK_M(MILLISECOND);
03026 break;
03027
03028 case DTK_SECOND:
03029 tm->tm_sec += val;
03030 #ifdef HAVE_INT64_TIMESTAMP
03031 *fsec += rint(fval * 1000000);
03032 #else
03033 *fsec += fval;
03034 #endif
03035
03036
03037
03038
03039
03040 if (fval == 0)
03041 tmask = DTK_M(SECOND);
03042 else
03043 tmask = DTK_ALL_SECS_M;
03044 break;
03045
03046 case DTK_MINUTE:
03047 tm->tm_min += val;
03048 AdjustFractSeconds(fval, tm, fsec, SECS_PER_MINUTE);
03049 tmask = DTK_M(MINUTE);
03050 break;
03051
03052 case DTK_HOUR:
03053 tm->tm_hour += val;
03054 AdjustFractSeconds(fval, tm, fsec, SECS_PER_HOUR);
03055 tmask = DTK_M(HOUR);
03056 type = DTK_DAY;
03057 break;
03058
03059 case DTK_DAY:
03060 tm->tm_mday += val;
03061 AdjustFractSeconds(fval, tm, fsec, SECS_PER_DAY);
03062 tmask = DTK_M(DAY);
03063 break;
03064
03065 case DTK_WEEK:
03066 tm->tm_mday += val * 7;
03067 AdjustFractDays(fval, tm, fsec, 7);
03068 tmask = DTK_M(WEEK);
03069 break;
03070
03071 case DTK_MONTH:
03072 tm->tm_mon += val;
03073 AdjustFractDays(fval, tm, fsec, DAYS_PER_MONTH);
03074 tmask = DTK_M(MONTH);
03075 break;
03076
03077 case DTK_YEAR:
03078 tm->tm_year += val;
03079 if (fval != 0)
03080 tm->tm_mon += fval * MONTHS_PER_YEAR;
03081 tmask = DTK_M(YEAR);
03082 break;
03083
03084 case DTK_DECADE:
03085 tm->tm_year += val * 10;
03086 if (fval != 0)
03087 tm->tm_mon += fval * MONTHS_PER_YEAR * 10;
03088 tmask = DTK_M(DECADE);
03089 break;
03090
03091 case DTK_CENTURY:
03092 tm->tm_year += val * 100;
03093 if (fval != 0)
03094 tm->tm_mon += fval * MONTHS_PER_YEAR * 100;
03095 tmask = DTK_M(CENTURY);
03096 break;
03097
03098 case DTK_MILLENNIUM:
03099 tm->tm_year += val * 1000;
03100 if (fval != 0)
03101 tm->tm_mon += fval * MONTHS_PER_YEAR * 1000;
03102 tmask = DTK_M(MILLENNIUM);
03103 break;
03104
03105 default:
03106 return DTERR_BAD_FORMAT;
03107 }
03108 break;
03109
03110 case DTK_STRING:
03111 case DTK_SPECIAL:
03112 type = DecodeUnits(i, field[i], &val);
03113 if (type == IGNORE_DTF)
03114 continue;
03115
03116 tmask = 0;
03117 switch (type)
03118 {
03119 case UNITS:
03120 type = val;
03121 break;
03122
03123 case AGO:
03124 is_before = TRUE;
03125 type = val;
03126 break;
03127
03128 case RESERV:
03129 tmask = (DTK_DATE_M | DTK_TIME_M);
03130 *dtype = val;
03131 break;
03132
03133 default:
03134 return DTERR_BAD_FORMAT;
03135 }
03136 break;
03137
03138 default:
03139 return DTERR_BAD_FORMAT;
03140 }
03141
03142 if (tmask & fmask)
03143 return DTERR_BAD_FORMAT;
03144 fmask |= tmask;
03145 }
03146
03147
03148 if (fmask == 0)
03149 return DTERR_BAD_FORMAT;
03150
03151
03152 if (*fsec != 0)
03153 {
03154 int sec;
03155
03156 #ifdef HAVE_INT64_TIMESTAMP
03157 sec = *fsec / USECS_PER_SEC;
03158 *fsec -= sec * USECS_PER_SEC;
03159 #else
03160 TMODULO(*fsec, sec, 1.0);
03161 #endif
03162 tm->tm_sec += sec;
03163 }
03164
03165
03166
03167
03168
03169
03170
03171
03172
03173
03174
03175
03176
03177
03178
03179
03180
03181 if (IntervalStyle == INTSTYLE_SQL_STANDARD && *field[0] == '-')
03182 {
03183
03184 bool more_signs = false;
03185
03186 for (i = 1; i < nf; i++)
03187 {
03188 if (*field[i] == '-' || *field[i] == '+')
03189 {
03190 more_signs = true;
03191 break;
03192 }
03193 }
03194
03195 if (!more_signs)
03196 {
03197
03198
03199
03200
03201 if (*fsec > 0)
03202 *fsec = -(*fsec);
03203 if (tm->tm_sec > 0)
03204 tm->tm_sec = -tm->tm_sec;
03205 if (tm->tm_min > 0)
03206 tm->tm_min = -tm->tm_min;
03207 if (tm->tm_hour > 0)
03208 tm->tm_hour = -tm->tm_hour;
03209 if (tm->tm_mday > 0)
03210 tm->tm_mday = -tm->tm_mday;
03211 if (tm->tm_mon > 0)
03212 tm->tm_mon = -tm->tm_mon;
03213 if (tm->tm_year > 0)
03214 tm->tm_year = -tm->tm_year;
03215 }
03216 }
03217
03218
03219 if (is_before)
03220 {
03221 *fsec = -(*fsec);
03222 tm->tm_sec = -tm->tm_sec;
03223 tm->tm_min = -tm->tm_min;
03224 tm->tm_hour = -tm->tm_hour;
03225 tm->tm_mday = -tm->tm_mday;
03226 tm->tm_mon = -tm->tm_mon;
03227 tm->tm_year = -tm->tm_year;
03228 }
03229
03230 return 0;
03231 }
03232
03233
03234
03235
03236
03237
03238
03239
03240 static int
03241 ParseISO8601Number(char *str, char **endptr, int *ipart, double *fpart)
03242 {
03243 double val;
03244
03245 if (!(isdigit((unsigned char) *str) || *str == '-' || *str == '.'))
03246 return DTERR_BAD_FORMAT;
03247 errno = 0;
03248 val = strtod(str, endptr);
03249
03250 if (*endptr == str || errno != 0)
03251 return DTERR_BAD_FORMAT;
03252
03253 if (val < INT_MIN || val > INT_MAX)
03254 return DTERR_FIELD_OVERFLOW;
03255
03256 if (val >= 0)
03257 *ipart = (int) floor(val);
03258 else
03259 *ipart = (int) -floor(-val);
03260 *fpart = val - *ipart;
03261 return 0;
03262 }
03263
03264
03265
03266
03267
03268 static int
03269 ISO8601IntegerWidth(char *fieldstart)
03270 {
03271
03272 if (*fieldstart == '-')
03273 fieldstart++;
03274 return strspn(fieldstart, "0123456789");
03275 }
03276
03277
03278
03279
03280
03281
03282
03283
03284
03285
03286
03287
03288
03289
03290
03291
03292
03293
03294
03295 int
03296 DecodeISO8601Interval(char *str,
03297 int *dtype, struct pg_tm * tm, fsec_t *fsec)
03298 {
03299 bool datepart = true;
03300 bool havefield = false;
03301
03302 *dtype = DTK_DELTA;
03303 ClearPgTm(tm, fsec);
03304
03305 if (strlen(str) < 2 || str[0] != 'P')
03306 return DTERR_BAD_FORMAT;
03307
03308 str++;
03309 while (*str)
03310 {
03311 char *fieldstart;
03312 int val;
03313 double fval;
03314 char unit;
03315 int dterr;
03316
03317 if (*str == 'T')
03318 {
03319 datepart = false;
03320 havefield = false;
03321 str++;
03322 continue;
03323 }
03324
03325 fieldstart = str;
03326 dterr = ParseISO8601Number(str, &str, &val, &fval);
03327 if (dterr)
03328 return dterr;
03329
03330
03331
03332
03333
03334 unit = *str++;
03335
03336 if (datepart)
03337 {
03338 switch (unit)
03339 {
03340 case 'Y':
03341 tm->tm_year += val;
03342 tm->tm_mon += (fval * MONTHS_PER_YEAR);
03343 break;
03344 case 'M':
03345 tm->tm_mon += val;
03346 AdjustFractDays(fval, tm, fsec, DAYS_PER_MONTH);
03347 break;
03348 case 'W':
03349 tm->tm_mday += val * 7;
03350 AdjustFractDays(fval, tm, fsec, 7);
03351 break;
03352 case 'D':
03353 tm->tm_mday += val;
03354 AdjustFractSeconds(fval, tm, fsec, SECS_PER_DAY);
03355 break;
03356 case 'T':
03357 case '\0':
03358 if (ISO8601IntegerWidth(fieldstart) == 8 && !havefield)
03359 {
03360 tm->tm_year += val / 10000;
03361 tm->tm_mon += (val / 100) % 100;
03362 tm->tm_mday += val % 100;
03363 AdjustFractSeconds(fval, tm, fsec, SECS_PER_DAY);
03364 if (unit == '\0')
03365 return 0;
03366 datepart = false;
03367 havefield = false;
03368 continue;
03369 }
03370
03371 case '-':
03372
03373 if (havefield)
03374 return DTERR_BAD_FORMAT;
03375
03376 tm->tm_year += val;
03377 tm->tm_mon += (fval * MONTHS_PER_YEAR);
03378 if (unit == '\0')
03379 return 0;
03380 if (unit == 'T')
03381 {
03382 datepart = false;
03383 havefield = false;
03384 continue;
03385 }
03386
03387 dterr = ParseISO8601Number(str, &str, &val, &fval);
03388 if (dterr)
03389 return dterr;
03390 tm->tm_mon += val;
03391 AdjustFractDays(fval, tm, fsec, DAYS_PER_MONTH);
03392 if (*str == '\0')
03393 return 0;
03394 if (*str == 'T')
03395 {
03396 datepart = false;
03397 havefield = false;
03398 continue;
03399 }
03400 if (*str != '-')
03401 return DTERR_BAD_FORMAT;
03402 str++;
03403
03404 dterr = ParseISO8601Number(str, &str, &val, &fval);
03405 if (dterr)
03406 return dterr;
03407 tm->tm_mday += val;
03408 AdjustFractSeconds(fval, tm, fsec, SECS_PER_DAY);
03409 if (*str == '\0')
03410 return 0;
03411 if (*str == 'T')
03412 {
03413 datepart = false;
03414 havefield = false;
03415 continue;
03416 }
03417 return DTERR_BAD_FORMAT;
03418 default:
03419
03420 return DTERR_BAD_FORMAT;
03421 }
03422 }
03423 else
03424 {
03425 switch (unit)
03426 {
03427 case 'H':
03428 tm->tm_hour += val;
03429 AdjustFractSeconds(fval, tm, fsec, SECS_PER_HOUR);
03430 break;
03431 case 'M':
03432 tm->tm_min += val;
03433 AdjustFractSeconds(fval, tm, fsec, SECS_PER_MINUTE);
03434 break;
03435 case 'S':
03436 tm->tm_sec += val;
03437 AdjustFractSeconds(fval, tm, fsec, 1);
03438 break;
03439 case '\0':
03440 if (ISO8601IntegerWidth(fieldstart) == 6 && !havefield)
03441 {
03442 tm->tm_hour += val / 10000;
03443 tm->tm_min += (val / 100) % 100;
03444 tm->tm_sec += val % 100;
03445 AdjustFractSeconds(fval, tm, fsec, 1);
03446 return 0;
03447 }
03448
03449 case ':':
03450
03451 if (havefield)
03452 return DTERR_BAD_FORMAT;
03453
03454 tm->tm_hour += val;
03455 AdjustFractSeconds(fval, tm, fsec, SECS_PER_HOUR);
03456 if (unit == '\0')
03457 return 0;
03458
03459 dterr = ParseISO8601Number(str, &str, &val, &fval);
03460 if (dterr)
03461 return dterr;
03462 tm->tm_min += val;
03463 AdjustFractSeconds(fval, tm, fsec, SECS_PER_MINUTE);
03464 if (*str == '\0')
03465 return 0;
03466 if (*str != ':')
03467 return DTERR_BAD_FORMAT;
03468 str++;
03469
03470 dterr = ParseISO8601Number(str, &str, &val, &fval);
03471 if (dterr)
03472 return dterr;
03473 tm->tm_sec += val;
03474 AdjustFractSeconds(fval, tm, fsec, 1);
03475 if (*str == '\0')
03476 return 0;
03477 return DTERR_BAD_FORMAT;
03478
03479 default:
03480
03481 return DTERR_BAD_FORMAT;
03482 }
03483 }
03484
03485 havefield = true;
03486 }
03487
03488 return 0;
03489 }
03490
03491
03492
03493
03494
03495
03496
03497 int
03498 DecodeUnits(int field, char *lowtoken, int *val)
03499 {
03500 int type;
03501 const datetkn *tp;
03502
03503 tp = deltacache[field];
03504 if (tp == NULL || strncmp(lowtoken, tp->token, TOKMAXLEN) != 0)
03505 {
03506 tp = datebsearch(lowtoken, deltatktbl, szdeltatktbl);
03507 }
03508 if (tp == NULL)
03509 {
03510 type = UNKNOWN_FIELD;
03511 *val = 0;
03512 }
03513 else
03514 {
03515 deltacache[field] = tp;
03516 type = tp->type;
03517 if (type == TZ || type == DTZ)
03518 *val = FROMVAL(tp);
03519 else
03520 *val = tp->value;
03521 }
03522
03523 return type;
03524 }
03525
03526
03527
03528
03529
03530
03531
03532
03533
03534
03535
03536 void
03537 DateTimeParseError(int dterr, const char *str, const char *datatype)
03538 {
03539 switch (dterr)
03540 {
03541 case DTERR_FIELD_OVERFLOW:
03542 ereport(ERROR,
03543 (errcode(ERRCODE_DATETIME_FIELD_OVERFLOW),
03544 errmsg("date/time field value out of range: \"%s\"",
03545 str)));
03546 break;
03547 case DTERR_MD_FIELD_OVERFLOW:
03548
03549 ereport(ERROR,
03550 (errcode(ERRCODE_DATETIME_FIELD_OVERFLOW),
03551 errmsg("date/time field value out of range: \"%s\"",
03552 str),
03553 errhint("Perhaps you need a different \"datestyle\" setting.")));
03554 break;
03555 case DTERR_INTERVAL_OVERFLOW:
03556 ereport(ERROR,
03557 (errcode(ERRCODE_INTERVAL_FIELD_OVERFLOW),
03558 errmsg("interval field value out of range: \"%s\"",
03559 str)));
03560 break;
03561 case DTERR_TZDISP_OVERFLOW:
03562 ereport(ERROR,
03563 (errcode(ERRCODE_INVALID_TIME_ZONE_DISPLACEMENT_VALUE),
03564 errmsg("time zone displacement out of range: \"%s\"",
03565 str)));
03566 break;
03567 case DTERR_BAD_FORMAT:
03568 default:
03569 ereport(ERROR,
03570 (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
03571 errmsg("invalid input syntax for type %s: \"%s\"",
03572 datatype, str)));
03573 break;
03574 }
03575 }
03576
03577
03578
03579
03580
03581 static const datetkn *
03582 datebsearch(const char *key, const datetkn *base, int nel)
03583 {
03584 if (nel > 0)
03585 {
03586 const datetkn *last = base + nel - 1,
03587 *position;
03588 int result;
03589
03590 while (last >= base)
03591 {
03592 position = base + ((last - base) >> 1);
03593 result = key[0] - position->token[0];
03594 if (result == 0)
03595 {
03596 result = strncmp(key, position->token, TOKMAXLEN);
03597 if (result == 0)
03598 return position;
03599 }
03600 if (result < 0)
03601 last = position - 1;
03602 else
03603 base = position + 1;
03604 }
03605 }
03606 return NULL;
03607 }
03608
03609
03610
03611
03612 static void
03613 EncodeTimezone(char *str, int tz, int style)
03614 {
03615 int hour,
03616 min,
03617 sec;
03618
03619 sec = abs(tz);
03620 min = sec / SECS_PER_MINUTE;
03621 sec -= min * SECS_PER_MINUTE;
03622 hour = min / MINS_PER_HOUR;
03623 min -= hour * MINS_PER_HOUR;
03624
03625 str += strlen(str);
03626
03627 *str++ = (tz <= 0 ? '+' : '-');
03628
03629 if (sec != 0)
03630 sprintf(str, "%02d:%02d:%02d", hour, min, sec);
03631 else if (min != 0 || style == USE_XSD_DATES)
03632 sprintf(str, "%02d:%02d", hour, min);
03633 else
03634 sprintf(str, "%02d", hour);
03635 }
03636
03637
03638
03639
03640 void
03641 EncodeDateOnly(struct pg_tm * tm, int style, char *str)
03642 {
03643 Assert(tm->tm_mon >= 1 && tm->tm_mon <= MONTHS_PER_YEAR);
03644
03645 switch (style)
03646 {
03647 case USE_ISO_DATES:
03648 case USE_XSD_DATES:
03649
03650 if (tm->tm_year > 0)
03651 sprintf(str, "%04d-%02d-%02d",
03652 tm->tm_year, tm->tm_mon, tm->tm_mday);
03653 else
03654 sprintf(str, "%04d-%02d-%02d %s",
03655 -(tm->tm_year - 1), tm->tm_mon, tm->tm_mday, "BC");
03656 break;
03657
03658 case USE_SQL_DATES:
03659
03660 if (DateOrder == DATEORDER_DMY)
03661 sprintf(str, "%02d/%02d", tm->tm_mday, tm->tm_mon);
03662 else
03663 sprintf(str, "%02d/%02d", tm->tm_mon, tm->tm_mday);
03664 if (tm->tm_year > 0)
03665 sprintf(str + 5, "/%04d", tm->tm_year);
03666 else
03667 sprintf(str + 5, "/%04d %s", -(tm->tm_year - 1), "BC");
03668 break;
03669
03670 case USE_GERMAN_DATES:
03671
03672 sprintf(str, "%02d.%02d", tm->tm_mday, tm->tm_mon);
03673 if (tm->tm_year > 0)
03674 sprintf(str + 5, ".%04d", tm->tm_year);
03675 else
03676 sprintf(str + 5, ".%04d %s", -(tm->tm_year - 1), "BC");
03677 break;
03678
03679 case USE_POSTGRES_DATES:
03680 default:
03681
03682 if (DateOrder == DATEORDER_DMY)
03683 sprintf(str, "%02d-%02d", tm->tm_mday, tm->tm_mon);
03684 else
03685 sprintf(str, "%02d-%02d", tm->tm_mon, tm->tm_mday);
03686 if (tm->tm_year > 0)
03687 sprintf(str + 5, "-%04d", tm->tm_year);
03688 else
03689 sprintf(str + 5, "-%04d %s", -(tm->tm_year - 1), "BC");
03690 break;
03691 }
03692 }
03693
03694
03695
03696
03697
03698
03699
03700
03701
03702
03703 void
03704 EncodeTimeOnly(struct pg_tm * tm, fsec_t fsec, bool print_tz, int tz, int style, char *str)
03705 {
03706 sprintf(str, "%02d:%02d:", tm->tm_hour, tm->tm_min);
03707 str += strlen(str);
03708
03709 AppendSeconds(str, tm->tm_sec, fsec, MAX_TIME_PRECISION, true);
03710
03711 if (print_tz)
03712 EncodeTimezone(str, tz, style);
03713 }
03714
03715
03716
03717
03718
03719
03720
03721
03722
03723
03724
03725
03726
03727
03728
03729
03730
03731
03732 void
03733 EncodeDateTime(struct pg_tm * tm, fsec_t fsec, bool print_tz, int tz, const char *tzn, int style, char *str)
03734 {
03735 int day;
03736
03737 Assert(tm->tm_mon >= 1 && tm->tm_mon <= MONTHS_PER_YEAR);
03738
03739
03740
03741
03742 if (tm->tm_isdst < 0)
03743 print_tz = false;
03744
03745 switch (style)
03746 {
03747 case USE_ISO_DATES:
03748 case USE_XSD_DATES:
03749
03750
03751 if (style == USE_ISO_DATES)
03752 sprintf(str, "%04d-%02d-%02d %02d:%02d:",
03753 (tm->tm_year > 0) ? tm->tm_year : -(tm->tm_year - 1),
03754 tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min);
03755 else
03756 sprintf(str, "%04d-%02d-%02dT%02d:%02d:",
03757 (tm->tm_year > 0) ? tm->tm_year : -(tm->tm_year - 1),
03758 tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min);
03759
03760 AppendTimestampSeconds(str + strlen(str), tm, fsec);
03761
03762 if (print_tz)
03763 EncodeTimezone(str, tz, style);
03764
03765 if (tm->tm_year <= 0)
03766 sprintf(str + strlen(str), " BC");
03767 break;
03768
03769 case USE_SQL_DATES:
03770
03771
03772 if (DateOrder == DATEORDER_DMY)
03773 sprintf(str, "%02d/%02d", tm->tm_mday, tm->tm_mon);
03774 else
03775 sprintf(str, "%02d/%02d", tm->tm_mon, tm->tm_mday);
03776
03777 sprintf(str + 5, "/%04d %02d:%02d:",
03778 (tm->tm_year > 0) ? tm->tm_year : -(tm->tm_year - 1),
03779 tm->tm_hour, tm->tm_min);
03780
03781 AppendTimestampSeconds(str + strlen(str), tm, fsec);
03782
03783
03784
03785
03786
03787
03788
03789 if (print_tz)
03790 {
03791 if (tzn)
03792 sprintf(str + strlen(str), " %.*s", MAXTZLEN, tzn);
03793 else
03794 EncodeTimezone(str, tz, style);
03795 }
03796
03797 if (tm->tm_year <= 0)
03798 sprintf(str + strlen(str), " BC");
03799 break;
03800
03801 case USE_GERMAN_DATES:
03802
03803
03804 sprintf(str, "%02d.%02d", tm->tm_mday, tm->tm_mon);
03805
03806 sprintf(str + 5, ".%04d %02d:%02d:",
03807 (tm->tm_year > 0) ? tm->tm_year : -(tm->tm_year - 1),
03808 tm->tm_hour, tm->tm_min);
03809
03810 AppendTimestampSeconds(str + strlen(str), tm, fsec);
03811
03812 if (print_tz)
03813 {
03814 if (tzn)
03815 sprintf(str + strlen(str), " %.*s", MAXTZLEN, tzn);
03816 else
03817 EncodeTimezone(str, tz, style);
03818 }
03819
03820 if (tm->tm_year <= 0)
03821 sprintf(str + strlen(str), " BC");
03822 break;
03823
03824 case USE_POSTGRES_DATES:
03825 default:
03826
03827
03828 day = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday);
03829 tm->tm_wday = j2day(day);
03830
03831 strncpy(str, days[tm->tm_wday], 3);
03832 strcpy(str + 3, " ");
03833
03834 if (DateOrder == DATEORDER_DMY)
03835 sprintf(str + 4, "%02d %3s", tm->tm_mday, months[tm->tm_mon - 1]);
03836 else
03837 sprintf(str + 4, "%3s %02d", months[tm->tm_mon - 1], tm->tm_mday);
03838
03839 sprintf(str + 10, " %02d:%02d:", tm->tm_hour, tm->tm_min);
03840
03841 AppendTimestampSeconds(str + strlen(str), tm, fsec);
03842
03843 sprintf(str + strlen(str), " %04d",
03844 (tm->tm_year > 0) ? tm->tm_year : -(tm->tm_year - 1));
03845
03846 if (print_tz)
03847 {
03848 if (tzn)
03849 sprintf(str + strlen(str), " %.*s", MAXTZLEN, tzn);
03850 else
03851 {
03852
03853
03854
03855
03856
03857
03858 sprintf(str + strlen(str), " ");
03859 EncodeTimezone(str, tz, style);
03860 }
03861 }
03862
03863 if (tm->tm_year <= 0)
03864 sprintf(str + strlen(str), " BC");
03865 break;
03866 }
03867 }
03868
03869
03870
03871
03872
03873
03874
03875 static char *
03876 AddISO8601IntPart(char *cp, int value, char units)
03877 {
03878 if (value == 0)
03879 return cp;
03880 sprintf(cp, "%d%c", value, units);
03881 return cp + strlen(cp);
03882 }
03883
03884
03885 static char *
03886 AddPostgresIntPart(char *cp, int value, const char *units,
03887 bool *is_zero, bool *is_before)
03888 {
03889 if (value == 0)
03890 return cp;
03891 sprintf(cp, "%s%s%d %s%s",
03892 (!*is_zero) ? " " : "",
03893 (*is_before && value > 0) ? "+" : "",
03894 value,
03895 units,
03896 (value != 1) ? "s" : "");
03897
03898
03899
03900
03901
03902 *is_before = (value < 0);
03903 *is_zero = FALSE;
03904 return cp + strlen(cp);
03905 }
03906
03907
03908 static char *
03909 AddVerboseIntPart(char *cp, int value, const char *units,
03910 bool *is_zero, bool *is_before)
03911 {
03912 if (value == 0)
03913 return cp;
03914
03915 if (*is_zero)
03916 {
03917 *is_before = (value < 0);
03918 value = abs(value);
03919 }
03920 else if (*is_before)
03921 value = -value;
03922 sprintf(cp, " %d %s%s", value, units, (value == 1) ? "" : "s");
03923 *is_zero = FALSE;
03924 return cp + strlen(cp);
03925 }
03926
03927
03928
03929
03930
03931
03932
03933
03934
03935
03936
03937
03938
03939
03940
03941
03942
03943
03944
03945
03946
03947 void
03948 EncodeInterval(struct pg_tm * tm, fsec_t fsec, int style, char *str)
03949 {
03950 char *cp = str;
03951 int year = tm->tm_year;
03952 int mon = tm->tm_mon;
03953 int mday = tm->tm_mday;
03954 int hour = tm->tm_hour;
03955 int min = tm->tm_min;
03956 int sec = tm->tm_sec;
03957 bool is_before = FALSE;
03958 bool is_zero = TRUE;
03959
03960
03961
03962
03963
03964
03965
03966 switch (style)
03967 {
03968
03969 case INTSTYLE_SQL_STANDARD:
03970 {
03971 bool has_negative = year < 0 || mon < 0 ||
03972 mday < 0 || hour < 0 ||
03973 min < 0 || sec < 0 || fsec < 0;
03974 bool has_positive = year > 0 || mon > 0 ||
03975 mday > 0 || hour > 0 ||
03976 min > 0 || sec > 0 || fsec > 0;
03977 bool has_year_month = year != 0 || mon != 0;
03978 bool has_day_time = mday != 0 || hour != 0 ||
03979 min != 0 || sec != 0 || fsec != 0;
03980 bool has_day = mday != 0;
03981 bool sql_standard_value = !(has_negative && has_positive) &&
03982 !(has_year_month && has_day_time);
03983
03984
03985
03986
03987
03988 if (has_negative && sql_standard_value)
03989 {
03990 *cp++ = '-';
03991 year = -year;
03992 mon = -mon;
03993 mday = -mday;
03994 hour = -hour;
03995 min = -min;
03996 sec = -sec;
03997 fsec = -fsec;
03998 }
03999
04000 if (!has_negative && !has_positive)
04001 {
04002 sprintf(cp, "0");
04003 }
04004 else if (!sql_standard_value)
04005 {
04006
04007
04008
04009
04010
04011 char year_sign = (year < 0 || mon < 0) ? '-' : '+';
04012 char day_sign = (mday < 0) ? '-' : '+';
04013 char sec_sign = (hour < 0 || min < 0 ||
04014 sec < 0 || fsec < 0) ? '-' : '+';
04015
04016 sprintf(cp, "%c%d-%d %c%d %c%d:%02d:",
04017 year_sign, abs(year), abs(mon),
04018 day_sign, abs(mday),
04019 sec_sign, abs(hour), abs(min));
04020 cp += strlen(cp);
04021 AppendSeconds(cp, sec, fsec, MAX_INTERVAL_PRECISION, true);
04022 }
04023 else if (has_year_month)
04024 {
04025 sprintf(cp, "%d-%d", year, mon);
04026 }
04027 else if (has_day)
04028 {
04029 sprintf(cp, "%d %d:%02d:", mday, hour, min);
04030 cp += strlen(cp);
04031 AppendSeconds(cp, sec, fsec, MAX_INTERVAL_PRECISION, true);
04032 }
04033 else
04034 {
04035 sprintf(cp, "%d:%02d:", hour, min);
04036 cp += strlen(cp);
04037 AppendSeconds(cp, sec, fsec, MAX_INTERVAL_PRECISION, true);
04038 }
04039 }
04040 break;
04041
04042
04043 case INTSTYLE_ISO_8601:
04044
04045 if (year == 0 && mon == 0 && mday == 0 &&
04046 hour == 0 && min == 0 && sec == 0 && fsec == 0)
04047 {
04048 sprintf(cp, "PT0S");
04049 break;
04050 }
04051 *cp++ = 'P';
04052 cp = AddISO8601IntPart(cp, year, 'Y');
04053 cp = AddISO8601IntPart(cp, mon, 'M');
04054 cp = AddISO8601IntPart(cp, mday, 'D');
04055 if (hour != 0 || min != 0 || sec != 0 || fsec != 0)
04056 *cp++ = 'T';
04057 cp = AddISO8601IntPart(cp, hour, 'H');
04058 cp = AddISO8601IntPart(cp, min, 'M');
04059 if (sec != 0 || fsec != 0)
04060 {
04061 if (sec < 0 || fsec < 0)
04062 *cp++ = '-';
04063 AppendSeconds(cp, sec, fsec, MAX_INTERVAL_PRECISION, false);
04064 cp += strlen(cp);
04065 *cp++ = 'S';
04066 *cp++ = '\0';
04067 }
04068 break;
04069
04070
04071 case INTSTYLE_POSTGRES:
04072 cp = AddPostgresIntPart(cp, year, "year", &is_zero, &is_before);
04073
04074
04075
04076
04077
04078
04079 cp = AddPostgresIntPart(cp, mon, "mon", &is_zero, &is_before);
04080 cp = AddPostgresIntPart(cp, mday, "day", &is_zero, &is_before);
04081 if (is_zero || hour != 0 || min != 0 || sec != 0 || fsec != 0)
04082 {
04083 bool minus = (hour < 0 || min < 0 || sec < 0 || fsec < 0);
04084
04085 sprintf(cp, "%s%s%02d:%02d:",
04086 is_zero ? "" : " ",
04087 (minus ? "-" : (is_before ? "+" : "")),
04088 abs(hour), abs(min));
04089 cp += strlen(cp);
04090 AppendSeconds(cp, sec, fsec, MAX_INTERVAL_PRECISION, true);
04091 }
04092 break;
04093
04094
04095 case INTSTYLE_POSTGRES_VERBOSE:
04096 default:
04097 strcpy(cp, "@");
04098 cp++;
04099 cp = AddVerboseIntPart(cp, year, "year", &is_zero, &is_before);
04100 cp = AddVerboseIntPart(cp, mon, "mon", &is_zero, &is_before);
04101 cp = AddVerboseIntPart(cp, mday, "day", &is_zero, &is_before);
04102 cp = AddVerboseIntPart(cp, hour, "hour", &is_zero, &is_before);
04103 cp = AddVerboseIntPart(cp, min, "min", &is_zero, &is_before);
04104 if (sec != 0 || fsec != 0)
04105 {
04106 *cp++ = ' ';
04107 if (sec < 0 || (sec == 0 && fsec < 0))
04108 {
04109 if (is_zero)
04110 is_before = TRUE;
04111 else if (!is_before)
04112 *cp++ = '-';
04113 }
04114 else if (is_before)
04115 *cp++ = '-';
04116 AppendSeconds(cp, sec, fsec, MAX_INTERVAL_PRECISION, false);
04117 cp += strlen(cp);
04118 sprintf(cp, " sec%s",
04119 (abs(sec) != 1 || fsec != 0) ? "s" : "");
04120 is_zero = FALSE;
04121 }
04122
04123 if (is_zero)
04124 strcat(cp, " 0");
04125 if (is_before)
04126 strcat(cp, " ago");
04127 break;
04128 }
04129 }
04130
04131
04132
04133
04134
04135
04136 static bool
04137 CheckDateTokenTable(const char *tablename, const datetkn *base, int nel)
04138 {
04139 bool ok = true;
04140 int i;
04141
04142 for (i = 1; i < nel; i++)
04143 {
04144 if (strncmp(base[i - 1].token, base[i].token, TOKMAXLEN) >= 0)
04145 {
04146
04147 elog(LOG, "ordering error in %s table: \"%.*s\" >= \"%.*s\"",
04148 tablename,
04149 TOKMAXLEN, base[i - 1].token,
04150 TOKMAXLEN, base[i].token);
04151 ok = false;
04152 }
04153 }
04154 return ok;
04155 }
04156
04157 bool
04158 CheckDateTokenTables(void)
04159 {
04160 bool ok = true;
04161
04162 Assert(UNIX_EPOCH_JDATE == date2j(1970, 1, 1));
04163 Assert(POSTGRES_EPOCH_JDATE == date2j(2000, 1, 1));
04164
04165 ok &= CheckDateTokenTable("datetktbl", datetktbl, szdatetktbl);
04166 ok &= CheckDateTokenTable("deltatktbl", deltatktbl, szdeltatktbl);
04167 return ok;
04168 }
04169
04170
04171
04172
04173
04174
04175
04176
04177
04178
04179 Node *
04180 TemporalTransform(int32 max_precis, Node *node)
04181 {
04182 FuncExpr *expr = (FuncExpr *) node;
04183 Node *ret = NULL;
04184 Node *typmod;
04185
04186 Assert(IsA(expr, FuncExpr));
04187 Assert(list_length(expr->args) >= 2);
04188
04189 typmod = (Node *) lsecond(expr->args);
04190
04191 if (IsA(typmod, Const) &&!((Const *) typmod)->constisnull)
04192 {
04193 Node *source = (Node *) linitial(expr->args);
04194 int32 old_precis = exprTypmod(source);
04195 int32 new_precis = DatumGetInt32(((Const *) typmod)->constvalue);
04196
04197 if (new_precis < 0 || new_precis == max_precis ||
04198 (old_precis >= 0 && new_precis >= old_precis))
04199 ret = relabel_to_typmod(source, new_precis);
04200 }
04201
04202 return ret;
04203 }
04204
04205
04206
04207
04208
04209
04210
04211 void
04212 ConvertTimeZoneAbbrevs(TimeZoneAbbrevTable *tbl,
04213 struct tzEntry *abbrevs, int n)
04214 {
04215 datetkn *newtbl = tbl->abbrevs;
04216 int i;
04217
04218 tbl->numabbrevs = n;
04219 for (i = 0; i < n; i++)
04220 {
04221 strncpy(newtbl[i].token, abbrevs[i].abbrev, TOKMAXLEN);
04222 newtbl[i].type = abbrevs[i].is_dst ? DTZ : TZ;
04223 TOVAL(&newtbl[i], abbrevs[i].offset / MINS_PER_HOUR);
04224 }
04225
04226
04227 Assert(CheckDateTokenTable("timezone offset", newtbl, n));
04228 }
04229
04230
04231
04232
04233
04234
04235 void
04236 InstallTimeZoneAbbrevs(TimeZoneAbbrevTable *tbl)
04237 {
04238 int i;
04239
04240 timezonetktbl = tbl->abbrevs;
04241 sztimezonetktbl = tbl->numabbrevs;
04242
04243
04244 for (i = 0; i < MAXDATEFIELDS; i++)
04245 datecache[i] = NULL;
04246 }
04247
04248
04249
04250
04251
04252 Datum
04253 pg_timezone_abbrevs(PG_FUNCTION_ARGS)
04254 {
04255 FuncCallContext *funcctx;
04256 int *pindex;
04257 Datum result;
04258 HeapTuple tuple;
04259 Datum values[3];
04260 bool nulls[3];
04261 char buffer[TOKMAXLEN + 1];
04262 unsigned char *p;
04263 struct pg_tm tm;
04264 Interval *resInterval;
04265
04266
04267 if (SRF_IS_FIRSTCALL())
04268 {
04269 TupleDesc tupdesc;
04270 MemoryContext oldcontext;
04271
04272
04273 funcctx = SRF_FIRSTCALL_INIT();
04274
04275
04276
04277
04278 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
04279
04280
04281 pindex = (int *) palloc(sizeof(int));
04282 *pindex = 0;
04283 funcctx->user_fctx = (void *) pindex;
04284
04285
04286
04287
04288
04289 tupdesc = CreateTemplateTupleDesc(3, false);
04290 TupleDescInitEntry(tupdesc, (AttrNumber) 1, "abbrev",
04291 TEXTOID, -1, 0);
04292 TupleDescInitEntry(tupdesc, (AttrNumber) 2, "utc_offset",
04293 INTERVALOID, -1, 0);
04294 TupleDescInitEntry(tupdesc, (AttrNumber) 3, "is_dst",
04295 BOOLOID, -1, 0);
04296
04297 funcctx->tuple_desc = BlessTupleDesc(tupdesc);
04298 MemoryContextSwitchTo(oldcontext);
04299 }
04300
04301
04302 funcctx = SRF_PERCALL_SETUP();
04303 pindex = (int *) funcctx->user_fctx;
04304
04305 if (*pindex >= sztimezonetktbl)
04306 SRF_RETURN_DONE(funcctx);
04307
04308 MemSet(nulls, 0, sizeof(nulls));
04309
04310
04311
04312
04313
04314 strncpy(buffer, timezonetktbl[*pindex].token, TOKMAXLEN);
04315 buffer[TOKMAXLEN] = '\0';
04316 for (p = (unsigned char *) buffer; *p; p++)
04317 *p = pg_toupper(*p);
04318
04319 values[0] = CStringGetTextDatum(buffer);
04320
04321 MemSet(&tm, 0, sizeof(struct pg_tm));
04322 tm.tm_min = (-1) * FROMVAL(&timezonetktbl[*pindex]);
04323 resInterval = (Interval *) palloc(sizeof(Interval));
04324 tm2interval(&tm, 0, resInterval);
04325 values[1] = IntervalPGetDatum(resInterval);
04326
04327 Assert(timezonetktbl[*pindex].type == DTZ ||
04328 timezonetktbl[*pindex].type == TZ);
04329 values[2] = BoolGetDatum(timezonetktbl[*pindex].type == DTZ);
04330
04331 (*pindex)++;
04332
04333 tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
04334 result = HeapTupleGetDatum(tuple);
04335
04336 SRF_RETURN_NEXT(funcctx, result);
04337 }
04338
04339
04340
04341
04342
04343 Datum
04344 pg_timezone_names(PG_FUNCTION_ARGS)
04345 {
04346 MemoryContext oldcontext;
04347 FuncCallContext *funcctx;
04348 pg_tzenum *tzenum;
04349 pg_tz *tz;
04350 Datum result;
04351 HeapTuple tuple;
04352 Datum values[4];
04353 bool nulls[4];
04354 int tzoff;
04355 struct pg_tm tm;
04356 fsec_t fsec;
04357 const char *tzn;
04358 Interval *resInterval;
04359 struct pg_tm itm;
04360
04361
04362 if (SRF_IS_FIRSTCALL())
04363 {
04364 TupleDesc tupdesc;
04365
04366
04367 funcctx = SRF_FIRSTCALL_INIT();
04368
04369
04370
04371
04372 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
04373
04374
04375 tzenum = pg_tzenumerate_start();
04376 funcctx->user_fctx = (void *) tzenum;
04377
04378
04379
04380
04381
04382 tupdesc = CreateTemplateTupleDesc(4, false);
04383 TupleDescInitEntry(tupdesc, (AttrNumber) 1, "name",
04384 TEXTOID, -1, 0);
04385 TupleDescInitEntry(tupdesc, (AttrNumber) 2, "abbrev",
04386 TEXTOID, -1, 0);
04387 TupleDescInitEntry(tupdesc, (AttrNumber) 3, "utc_offset",
04388 INTERVALOID, -1, 0);
04389 TupleDescInitEntry(tupdesc, (AttrNumber) 4, "is_dst",
04390 BOOLOID, -1, 0);
04391
04392 funcctx->tuple_desc = BlessTupleDesc(tupdesc);
04393 MemoryContextSwitchTo(oldcontext);
04394 }
04395
04396
04397 funcctx = SRF_PERCALL_SETUP();
04398 tzenum = (pg_tzenum *) funcctx->user_fctx;
04399
04400
04401 for (;;)
04402 {
04403 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
04404 tz = pg_tzenumerate_next(tzenum);
04405 MemoryContextSwitchTo(oldcontext);
04406
04407 if (!tz)
04408 {
04409 pg_tzenumerate_end(tzenum);
04410 funcctx->user_fctx = NULL;
04411 SRF_RETURN_DONE(funcctx);
04412 }
04413
04414
04415 if (timestamp2tm(GetCurrentTransactionStartTimestamp(),
04416 &tzoff, &tm, &fsec, &tzn, tz) != 0)
04417 continue;
04418
04419
04420 if (tzn && strcmp(tzn, "Local time zone must be set--see zic manual page") == 0)
04421 continue;
04422
04423
04424 break;
04425 }
04426
04427 MemSet(nulls, 0, sizeof(nulls));
04428
04429 values[0] = CStringGetTextDatum(pg_get_timezone_name(tz));
04430 values[1] = CStringGetTextDatum(tzn ? tzn : "");
04431
04432 MemSet(&itm, 0, sizeof(struct pg_tm));
04433 itm.tm_sec = -tzoff;
04434 resInterval = (Interval *) palloc(sizeof(Interval));
04435 tm2interval(&itm, 0, resInterval);
04436 values[2] = IntervalPGetDatum(resInterval);
04437
04438 values[3] = BoolGetDatum(tm.tm_isdst > 0);
04439
04440 tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
04441 result = HeapTupleGetDatum(tuple);
04442
04443 SRF_RETURN_NEXT(funcctx, result);
04444 }