LCOV - code coverage report
Current view: top level - src/interfaces/ecpg/pgtypeslib - dt_common.c (source / functions) Hit Total Coverage
Test: PostgreSQL 17devel Lines: 708 1248 56.7 %
Date: 2024-03-28 10:11:15 Functions: 21 23 91.3 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* src/interfaces/ecpg/pgtypeslib/dt_common.c */
       2             : 
       3             : #include "postgres_fe.h"
       4             : 
       5             : #include <time.h>
       6             : #include <ctype.h>
       7             : #include <math.h>
       8             : 
       9             : #include "common/string.h"
      10             : #include "dt.h"
      11             : #include "pgtypes_timestamp.h"
      12             : #include "pgtypeslib_extern.h"
      13             : 
      14             : const int   day_tab[2][13] = {
      15             :     {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 0},
      16             : {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 0}};
      17             : 
      18             : typedef long AbsoluteTime;
      19             : 
      20             : static const datetkn datetktbl[] = {
      21             : /*  text, token, lexval */
      22             :     {EARLY, RESERV, DTK_EARLY}, /* "-infinity" reserved for "early time" */
      23             :     {"acsst", DTZ, 37800},        /* Cent. Australia */
      24             :     {"acst", DTZ, -14400},        /* Atlantic/Porto Acre */
      25             :     {"act", TZ, -18000},      /* Atlantic/Porto Acre */
      26             :     {DA_D, ADBC, AD},           /* "ad" for years >= 0 */
      27             :     {"adt", DTZ, -10800},     /* Atlantic Daylight Time */
      28             :     {"aesst", DTZ, 39600},        /* E. Australia */
      29             :     {"aest", TZ, 36000},      /* Australia Eastern Std Time */
      30             :     {"aft", TZ, 16200},           /* Kabul */
      31             :     {"ahst", TZ, -36000},     /* Alaska-Hawaii Std Time */
      32             :     {"akdt", DTZ, -28800},        /* Alaska Daylight Time */
      33             :     {"akst", DTZ, -32400},        /* Alaska Standard Time */
      34             :     {"allballs", RESERV, DTK_ZULU}, /* 00:00:00 */
      35             :     {"almst", TZ, 25200},     /* Almaty Savings Time */
      36             :     {"almt", TZ, 21600},      /* Almaty Time */
      37             :     {"am", AMPM, AM},
      38             :     {"amst", DTZ, 18000},     /* Armenia Summer Time (Yerevan) */
      39             : #if 0
      40             :     {"amst", DTZ, -10800},        /* Porto Velho */
      41             : #endif
      42             :     {"amt", TZ, 14400},           /* Armenia Time (Yerevan) */
      43             :     {"anast", DTZ, 46800},        /* Anadyr Summer Time (Russia) */
      44             :     {"anat", TZ, 43200},      /* Anadyr Time (Russia) */
      45             :     {"apr", MONTH, 4},
      46             :     {"april", MONTH, 4},
      47             : #if 0
      48             :     aqtst
      49             :     aqtt
      50             :     arst
      51             : #endif
      52             :     {"art", TZ, -10800},      /* Argentina Time */
      53             : #if 0
      54             :     ashst
      55             :     ast                         /* Atlantic Standard Time, Arabia Standard
      56             :                                  * Time, Acre Standard Time */
      57             : #endif
      58             :     {"ast", TZ, -14400},      /* Atlantic Std Time (Canada) */
      59             :     {"at", IGNORE_DTF, 0},        /* "at" (throwaway) */
      60             :     {"aug", MONTH, 8},
      61             :     {"august", MONTH, 8},
      62             :     {"awsst", DTZ, 32400},        /* W. Australia */
      63             :     {"awst", TZ, 28800},      /* W. Australia */
      64             :     {"awt", DTZ, -10800},
      65             :     {"azost", DTZ, 0},            /* Azores Summer Time */
      66             :     {"azot", TZ, -3600},      /* Azores Time */
      67             :     {"azst", DTZ, 18000},     /* Azerbaijan Summer Time */
      68             :     {"azt", TZ, 14400},           /* Azerbaijan Time */
      69             :     {DB_C, ADBC, BC},           /* "bc" for years < 0 */
      70             :     {"bdst", TZ, 7200},           /* British Double Summer Time */
      71             :     {"bdt", TZ, 21600},           /* Dacca */
      72             :     {"bnt", TZ, 28800},           /* Brunei Darussalam Time */
      73             :     {"bort", TZ, 28800},      /* Borneo Time (Indonesia) */
      74             : #if 0
      75             :     bortst
      76             :     bost
      77             : #endif
      78             :     {"bot", TZ, -14400},      /* Bolivia Time */
      79             :     {"bra", TZ, -10800},      /* Brazil Time */
      80             : #if 0
      81             :     brst
      82             :     brt
      83             : #endif
      84             :     {"bst", DTZ, 3600},           /* British Summer Time */
      85             : #if 0
      86             :     {"bst", TZ, -10800},      /* Brazil Standard Time */
      87             :     {"bst", DTZ, -39600},     /* Bering Summer Time */
      88             : #endif
      89             :     {"bt", TZ, 10800},            /* Baghdad Time */
      90             :     {"btt", TZ, 21600},           /* Bhutan Time */
      91             :     {"cadt", DTZ, 37800},     /* Central Australian DST */
      92             :     {"cast", TZ, 34200},      /* Central Australian ST */
      93             :     {"cat", TZ, -36000},      /* Central Alaska Time */
      94             :     {"cct", TZ, 28800},           /* China Coast Time */
      95             : #if 0
      96             :     {"cct", TZ, 23400},           /* Indian Cocos (Island) Time */
      97             : #endif
      98             :     {"cdt", DTZ, -18000},     /* Central Daylight Time */
      99             :     {"cest", DTZ, 7200},      /* Central European Dayl.Time */
     100             :     {"cet", TZ, 3600},            /* Central European Time */
     101             :     {"cetdst", DTZ, 7200},        /* Central European Dayl.Time */
     102             :     {"chadt", DTZ, 49500},        /* Chatham Island Daylight Time (13:45) */
     103             :     {"chast", TZ, 45900},     /* Chatham Island Time (12:45) */
     104             : #if 0
     105             :     ckhst
     106             : #endif
     107             :     {"ckt", TZ, 43200},           /* Cook Islands Time */
     108             :     {"clst", DTZ, -10800},        /* Chile Summer Time */
     109             :     {"clt", TZ, -14400},      /* Chile Time */
     110             : #if 0
     111             :     cost
     112             : #endif
     113             :     {"cot", TZ, -18000},      /* Columbia Time */
     114             :     {"cst", TZ, -21600},      /* Central Standard Time */
     115             : #if 0
     116             :     cvst
     117             : #endif
     118             :     {"cvt", TZ, 25200},           /* Christmas Island Time (Indian Ocean) */
     119             :     {"cxt", TZ, 25200},           /* Christmas Island Time (Indian Ocean) */
     120             :     {"d", UNITS, DTK_DAY},        /* "day of month" for ISO input */
     121             :     {"davt", TZ, 25200},      /* Davis Time (Antarctica) */
     122             :     {"ddut", TZ, 36000},      /* Dumont-d'Urville Time (Antarctica) */
     123             :     {"dec", MONTH, 12},
     124             :     {"december", MONTH, 12},
     125             :     {"dnt", TZ, 3600},            /* Dansk Normal Tid */
     126             :     {"dow", UNITS, DTK_DOW},  /* day of week */
     127             :     {"doy", UNITS, DTK_DOY},  /* day of year */
     128             :     {"dst", DTZMOD, SECS_PER_HOUR},
     129             : #if 0
     130             :     {"dusst", DTZ, 21600},        /* Dushanbe Summer Time */
     131             : #endif
     132             :     {"easst", DTZ, -18000},       /* Easter Island Summer Time */
     133             :     {"east", TZ, -21600},     /* Easter Island Time */
     134             :     {"eat", TZ, 10800},           /* East Africa Time */
     135             : #if 0
     136             :     {"east", DTZ, 14400},     /* Indian Antananarivo Savings Time */
     137             :     {"eat", TZ, 10800},           /* Indian Antananarivo Time */
     138             :     {"ect", TZ, -14400},      /* Eastern Caribbean Time */
     139             :     {"ect", TZ, -18000},      /* Ecuador Time */
     140             : #endif
     141             :     {"edt", DTZ, -14400},     /* Eastern Daylight Time */
     142             :     {"eest", DTZ, 10800},     /* Eastern Europe Summer Time */
     143             :     {"eet", TZ, 7200},            /* East. Europe, USSR Zone 1 */
     144             :     {"eetdst", DTZ, 10800},       /* Eastern Europe Daylight Time */
     145             :     {"egst", DTZ, 0},         /* East Greenland Summer Time */
     146             :     {"egt", TZ, -3600},           /* East Greenland Time */
     147             : #if 0
     148             :     ehdt
     149             : #endif
     150             :     {EPOCH, RESERV, DTK_EPOCH}, /* "epoch" reserved for system epoch time */
     151             :     {"est", TZ, -18000},      /* Eastern Standard Time */
     152             :     {"feb", MONTH, 2},
     153             :     {"february", MONTH, 2},
     154             :     {"fjst", DTZ, -46800},        /* Fiji Summer Time (13 hour offset!) */
     155             :     {"fjt", TZ, -43200},      /* Fiji Time */
     156             :     {"fkst", DTZ, -10800},        /* Falkland Islands Summer Time */
     157             :     {"fkt", TZ, -7200},           /* Falkland Islands Time */
     158             : #if 0
     159             :     fnst
     160             :     fnt
     161             : #endif
     162             :     {"fri", DOW, 5},
     163             :     {"friday", DOW, 5},
     164             :     {"fst", TZ, 3600},            /* French Summer Time */
     165             :     {"fwt", DTZ, 7200},           /* French Winter Time  */
     166             :     {"galt", TZ, -21600},     /* Galapagos Time */
     167             :     {"gamt", TZ, -32400},     /* Gambier Time */
     168             :     {"gest", DTZ, 18000},     /* Georgia Summer Time */
     169             :     {"get", TZ, 14400},           /* Georgia Time */
     170             :     {"gft", TZ, -10800},      /* French Guiana Time */
     171             : #if 0
     172             :     ghst
     173             : #endif
     174             :     {"gilt", TZ, 43200},      /* Gilbert Islands Time */
     175             :     {"gmt", TZ, 0},               /* Greenwich Mean Time */
     176             :     {"gst", TZ, 36000},           /* Guam Std Time, USSR Zone 9 */
     177             :     {"gyt", TZ, -14400},      /* Guyana Time */
     178             :     {"h", UNITS, DTK_HOUR},       /* "hour" */
     179             : #if 0
     180             :     hadt
     181             :     hast
     182             : #endif
     183             :     {"hdt", DTZ, -32400},     /* Hawaii/Alaska Daylight Time */
     184             : #if 0
     185             :     hkst
     186             : #endif
     187             :     {"hkt", TZ, 28800},           /* Hong Kong Time */
     188             : #if 0
     189             :     {"hmt", TZ, 10800},           /* Hellas ? ? */
     190             :     hovst
     191             :     hovt
     192             : #endif
     193             :     {"hst", TZ, -36000},      /* Hawaii Std Time */
     194             : #if 0
     195             :     hwt
     196             : #endif
     197             :     {"ict", TZ, 25200},           /* Indochina Time */
     198             :     {"idle", TZ, 43200},      /* Intl. Date Line, East */
     199             :     {"idlw", TZ, -43200},     /* Intl. Date Line, West */
     200             : #if 0
     201             :     idt                         /* Israeli, Iran, Indian Daylight Time */
     202             : #endif
     203             :     {LATE, RESERV, DTK_LATE},   /* "infinity" reserved for "late time" */
     204             :     {"iot", TZ, 18000},           /* Indian Chagos Time */
     205             :     {"irkst", DTZ, 32400},        /* Irkutsk Summer Time */
     206             :     {"irkt", TZ, 28800},      /* Irkutsk Time */
     207             :     {"irt", TZ, 12600},           /* Iran Time */
     208             :     {"isodow", UNITS, DTK_ISODOW},    /* ISO day of week, Sunday == 7 */
     209             : #if 0
     210             :     isst
     211             : #endif
     212             :     {"ist", TZ, 7200},            /* Israel */
     213             :     {"it", TZ, 12600},            /* Iran Time */
     214             :     {"j", UNITS, DTK_JULIAN},
     215             :     {"jan", MONTH, 1},
     216             :     {"january", MONTH, 1},
     217             :     {"javt", TZ, 25200},      /* Java Time (07:00? see JT) */
     218             :     {"jayt", TZ, 32400},      /* Jayapura Time (Indonesia) */
     219             :     {"jd", UNITS, DTK_JULIAN},
     220             :     {"jst", TZ, 32400},           /* Japan Std Time,USSR Zone 8 */
     221             :     {"jt", TZ, 27000},            /* Java Time (07:30? see JAVT) */
     222             :     {"jul", MONTH, 7},
     223             :     {"julian", UNITS, DTK_JULIAN},
     224             :     {"july", MONTH, 7},
     225             :     {"jun", MONTH, 6},
     226             :     {"june", MONTH, 6},
     227             :     {"kdt", DTZ, 36000},      /* Korea Daylight Time */
     228             :     {"kgst", DTZ, 21600},     /* Kyrgyzstan Summer Time */
     229             :     {"kgt", TZ, 18000},           /* Kyrgyzstan Time */
     230             :     {"kost", TZ, 43200},      /* Kosrae Time */
     231             :     {"krast", DTZ, 25200},        /* Krasnoyarsk Summer Time */
     232             :     {"krat", TZ, 28800},      /* Krasnoyarsk Standard Time */
     233             :     {"kst", TZ, 32400},           /* Korea Standard Time */
     234             :     {"lhdt", DTZ, 39600},     /* Lord Howe Daylight Time, Australia */
     235             :     {"lhst", TZ, 37800},      /* Lord Howe Standard Time, Australia */
     236             :     {"ligt", TZ, 36000},      /* From Melbourne, Australia */
     237             :     {"lint", TZ, 50400},      /* Line Islands Time (Kiribati; +14 hours!) */
     238             :     {"lkt", TZ, 21600},           /* Lanka Time */
     239             :     {"m", UNITS, DTK_MONTH},  /* "month" for ISO input */
     240             :     {"magst", DTZ, 43200},        /* Magadan Summer Time */
     241             :     {"magt", TZ, 39600},      /* Magadan Time */
     242             :     {"mar", MONTH, 3},
     243             :     {"march", MONTH, 3},
     244             :     {"mart", TZ, -34200},     /* Marquesas Time */
     245             :     {"mawt", TZ, 21600},      /* Mawson, Antarctica */
     246             :     {"may", MONTH, 5},
     247             :     {"mdt", DTZ, -21600},     /* Mountain Daylight Time */
     248             :     {"mest", DTZ, 7200},      /* Middle Europe Summer Time */
     249             :     {"met", TZ, 3600},            /* Middle Europe Time */
     250             :     {"metdst", DTZ, 7200},        /* Middle Europe Daylight Time */
     251             :     {"mewt", TZ, 3600},           /* Middle Europe Winter Time */
     252             :     {"mez", TZ, 3600},            /* Middle Europe Zone */
     253             :     {"mht", TZ, 43200},           /* Kwajalein */
     254             :     {"mm", UNITS, DTK_MINUTE},    /* "minute" for ISO input */
     255             :     {"mmt", TZ, 23400},           /* Myannar Time */
     256             :     {"mon", DOW, 1},
     257             :     {"monday", DOW, 1},
     258             : #if 0
     259             :     most
     260             : #endif
     261             :     {"mpt", TZ, 36000},           /* North Mariana Islands Time */
     262             :     {"msd", DTZ, 14400},      /* Moscow Summer Time */
     263             :     {"msk", TZ, 10800},           /* Moscow Time */
     264             :     {"mst", TZ, -25200},      /* Mountain Standard Time */
     265             :     {"mt", TZ, 30600},            /* Moluccas Time */
     266             :     {"mut", TZ, 14400},           /* Mauritius Island Time */
     267             :     {"mvt", TZ, 18000},           /* Maldives Island Time */
     268             :     {"myt", TZ, 28800},           /* Malaysia Time */
     269             : #if 0
     270             :     ncst
     271             : #endif
     272             :     {"nct", TZ, 39600},           /* New Caledonia Time */
     273             :     {"ndt", DTZ, -9000},      /* Nfld. Daylight Time */
     274             :     {"nft", TZ, -12600},      /* Newfoundland Standard Time */
     275             :     {"nor", TZ, 3600},            /* Norway Standard Time */
     276             :     {"nov", MONTH, 11},
     277             :     {"november", MONTH, 11},
     278             :     {"novst", DTZ, 25200},        /* Novosibirsk Summer Time */
     279             :     {"novt", TZ, 21600},      /* Novosibirsk Standard Time */
     280             :     {NOW, RESERV, DTK_NOW},     /* current transaction time */
     281             :     {"npt", TZ, 20700},           /* Nepal Standard Time (GMT-5:45) */
     282             :     {"nst", TZ, -12600},      /* Nfld. Standard Time */
     283             :     {"nt", TZ, -39600},           /* Nome Time */
     284             :     {"nut", TZ, -39600},      /* Niue Time */
     285             :     {"nzdt", DTZ, 46800},     /* New Zealand Daylight Time */
     286             :     {"nzst", TZ, 43200},      /* New Zealand Standard Time */
     287             :     {"nzt", TZ, 43200},           /* New Zealand Time */
     288             :     {"oct", MONTH, 10},
     289             :     {"october", MONTH, 10},
     290             :     {"omsst", DTZ, 25200},        /* Omsk Summer Time */
     291             :     {"omst", TZ, 21600},      /* Omsk Time */
     292             :     {"on", IGNORE_DTF, 0},        /* "on" (throwaway) */
     293             :     {"pdt", DTZ, -25200},     /* Pacific Daylight Time */
     294             : #if 0
     295             :     pest
     296             : #endif
     297             :     {"pet", TZ, -18000},      /* Peru Time */
     298             :     {"petst", DTZ, 46800},        /* Petropavlovsk-Kamchatski Summer Time */
     299             :     {"pett", TZ, 43200},      /* Petropavlovsk-Kamchatski Time */
     300             :     {"pgt", TZ, 36000},           /* Papua New Guinea Time */
     301             :     {"phot", TZ, 46800},      /* Phoenix Islands (Kiribati) Time */
     302             : #if 0
     303             :     phst
     304             : #endif
     305             :     {"pht", TZ, 28800},           /* Philippine Time */
     306             :     {"pkt", TZ, 18000},           /* Pakistan Time */
     307             :     {"pm", AMPM, PM},
     308             :     {"pmdt", DTZ, -7200},     /* Pierre & Miquelon Daylight Time */
     309             : #if 0
     310             :     pmst
     311             : #endif
     312             :     {"pont", TZ, 39600},      /* Ponape Time (Micronesia) */
     313             :     {"pst", TZ, -28800},      /* Pacific Standard Time */
     314             :     {"pwt", TZ, 32400},           /* Palau Time */
     315             :     {"pyst", DTZ, -10800},        /* Paraguay Summer Time */
     316             :     {"pyt", TZ, -14400},      /* Paraguay Time */
     317             :     {"ret", DTZ, 14400},      /* Reunion Island Time */
     318             :     {"s", UNITS, DTK_SECOND}, /* "seconds" for ISO input */
     319             :     {"sadt", DTZ, 37800},     /* S. Australian Dayl. Time */
     320             : #if 0
     321             :     samst
     322             :     samt
     323             : #endif
     324             :     {"sast", TZ, 34200},      /* South Australian Std Time */
     325             :     {"sat", DOW, 6},
     326             :     {"saturday", DOW, 6},
     327             : #if 0
     328             :     sbt
     329             : #endif
     330             :     {"sct", DTZ, 14400},      /* Mahe Island Time */
     331             :     {"sep", MONTH, 9},
     332             :     {"sept", MONTH, 9},
     333             :     {"september", MONTH, 9},
     334             :     {"set", TZ, -3600},           /* Seychelles Time ?? */
     335             : #if 0
     336             :     sgt
     337             : #endif
     338             :     {"sst", DTZ, 7200},           /* Swedish Summer Time */
     339             :     {"sun", DOW, 0},
     340             :     {"sunday", DOW, 0},
     341             :     {"swt", TZ, 3600},            /* Swedish Winter Time */
     342             : #if 0
     343             :     syot
     344             : #endif
     345             :     {"t", ISOTIME, DTK_TIME}, /* Filler for ISO time fields */
     346             :     {"tft", TZ, 18000},           /* Kerguelen Time */
     347             :     {"that", TZ, -36000},     /* Tahiti Time */
     348             :     {"thu", DOW, 4},
     349             :     {"thur", DOW, 4},
     350             :     {"thurs", DOW, 4},
     351             :     {"thursday", DOW, 4},
     352             :     {"tjt", TZ, 18000},           /* Tajikistan Time */
     353             :     {"tkt", TZ, -36000},      /* Tokelau Time */
     354             :     {"tmt", TZ, 18000},           /* Turkmenistan Time */
     355             :     {TODAY, RESERV, DTK_TODAY}, /* midnight */
     356             :     {TOMORROW, RESERV, DTK_TOMORROW},   /* tomorrow midnight */
     357             : #if 0
     358             :     tost
     359             : #endif
     360             :     {"tot", TZ, 46800},           /* Tonga Time */
     361             : #if 0
     362             :     tpt
     363             : #endif
     364             :     {"truk", TZ, 36000},      /* Truk Time */
     365             :     {"tue", DOW, 2},
     366             :     {"tues", DOW, 2},
     367             :     {"tuesday", DOW, 2},
     368             :     {"tvt", TZ, 43200},           /* Tuvalu Time */
     369             : #if 0
     370             :     uct
     371             : #endif
     372             :     {"ulast", DTZ, 32400},        /* Ulan Bator Summer Time */
     373             :     {"ulat", TZ, 28800},      /* Ulan Bator Time */
     374             :     {"ut", TZ, 0},
     375             :     {"utc", TZ, 0},
     376             :     {"uyst", DTZ, -7200},     /* Uruguay Summer Time */
     377             :     {"uyt", TZ, -10800},      /* Uruguay Time */
     378             :     {"uzst", DTZ, 21600},     /* Uzbekistan Summer Time */
     379             :     {"uzt", TZ, 18000},           /* Uzbekistan Time */
     380             :     {"vet", TZ, -14400},      /* Venezuela Time */
     381             :     {"vlast", DTZ, 39600},        /* Vladivostok Summer Time */
     382             :     {"vlat", TZ, 36000},      /* Vladivostok Time */
     383             : #if 0
     384             :     vust
     385             : #endif
     386             :     {"vut", TZ, 39600},           /* Vanuata Time */
     387             :     {"wadt", DTZ, 28800},     /* West Australian DST */
     388             :     {"wakt", TZ, 43200},      /* Wake Time */
     389             : #if 0
     390             :     warst
     391             : #endif
     392             :     {"wast", TZ, 25200},      /* West Australian Std Time */
     393             :     {"wat", TZ, -3600},           /* West Africa Time */
     394             :     {"wdt", DTZ, 32400},      /* West Australian DST */
     395             :     {"wed", DOW, 3},
     396             :     {"wednesday", DOW, 3},
     397             :     {"weds", DOW, 3},
     398             :     {"west", DTZ, 3600},      /* Western Europe Summer Time */
     399             :     {"wet", TZ, 0},               /* Western Europe */
     400             :     {"wetdst", DTZ, 3600},        /* Western Europe Daylight Savings Time */
     401             :     {"wft", TZ, 43200},           /* Wallis and Futuna Time */
     402             :     {"wgst", DTZ, -7200},     /* West Greenland Summer Time */
     403             :     {"wgt", TZ, -10800},      /* West Greenland Time */
     404             :     {"wst", TZ, 28800},           /* West Australian Standard Time */
     405             :     {"y", UNITS, DTK_YEAR},       /* "year" for ISO input */
     406             :     {"yakst", DTZ, 36000},        /* Yakutsk Summer Time */
     407             :     {"yakt", TZ, 32400},      /* Yakutsk Time */
     408             :     {"yapt", TZ, 36000},      /* Yap Time (Micronesia) */
     409             :     {"ydt", DTZ, -28800},     /* Yukon Daylight Time */
     410             :     {"yekst", DTZ, 21600},        /* Yekaterinburg Summer Time */
     411             :     {"yekt", TZ, 18000},      /* Yekaterinburg Time */
     412             :     {YESTERDAY, RESERV, DTK_YESTERDAY}, /* yesterday midnight */
     413             :     {"yst", TZ, -32400},      /* Yukon Standard Time */
     414             :     {"z", TZ, 0},             /* time zone tag per ISO-8601 */
     415             :     {"zp4", TZ, -14400},      /* UTC +4  hours. */
     416             :     {"zp5", TZ, -18000},      /* UTC +5  hours. */
     417             :     {"zp6", TZ, -21600},      /* UTC +6  hours. */
     418             :     {ZULU, TZ, 0},              /* UTC */
     419             : };
     420             : 
     421             : static const datetkn deltatktbl[] = {
     422             :     /* text, token, lexval */
     423             :     {"@", IGNORE_DTF, 0},     /* postgres relative prefix */
     424             :     {DAGO, AGO, 0},             /* "ago" indicates negative time offset */
     425             :     {"c", UNITS, DTK_CENTURY},    /* "century" relative */
     426             :     {"cent", UNITS, DTK_CENTURY}, /* "century" relative */
     427             :     {"centuries", UNITS, DTK_CENTURY},    /* "centuries" relative */
     428             :     {DCENTURY, UNITS, DTK_CENTURY}, /* "century" relative */
     429             :     {"d", UNITS, DTK_DAY},        /* "day" relative */
     430             :     {DDAY, UNITS, DTK_DAY},     /* "day" relative */
     431             :     {"days", UNITS, DTK_DAY}, /* "days" relative */
     432             :     {"dec", UNITS, DTK_DECADE}, /* "decade" relative */
     433             :     {DDECADE, UNITS, DTK_DECADE},   /* "decade" relative */
     434             :     {"decades", UNITS, DTK_DECADE}, /* "decades" relative */
     435             :     {"decs", UNITS, DTK_DECADE},  /* "decades" relative */
     436             :     {"h", UNITS, DTK_HOUR},       /* "hour" relative */
     437             :     {DHOUR, UNITS, DTK_HOUR},   /* "hour" relative */
     438             :     {"hours", UNITS, DTK_HOUR}, /* "hours" relative */
     439             :     {"hr", UNITS, DTK_HOUR},  /* "hour" relative */
     440             :     {"hrs", UNITS, DTK_HOUR}, /* "hours" relative */
     441             :     {"m", UNITS, DTK_MINUTE}, /* "minute" relative */
     442             :     {"microsecon", UNITS, DTK_MICROSEC},  /* "microsecond" relative */
     443             :     {"mil", UNITS, DTK_MILLENNIUM}, /* "millennium" relative */
     444             :     {"millennia", UNITS, DTK_MILLENNIUM}, /* "millennia" relative */
     445             :     {DMILLENNIUM, UNITS, DTK_MILLENNIUM},   /* "millennium" relative */
     446             :     {"millisecon", UNITS, DTK_MILLISEC},  /* relative */
     447             :     {"mils", UNITS, DTK_MILLENNIUM},  /* "millennia" relative */
     448             :     {"min", UNITS, DTK_MINUTE}, /* "minute" relative */
     449             :     {"mins", UNITS, DTK_MINUTE},  /* "minutes" relative */
     450             :     {DMINUTE, UNITS, DTK_MINUTE},   /* "minute" relative */
     451             :     {"minutes", UNITS, DTK_MINUTE}, /* "minutes" relative */
     452             :     {"mon", UNITS, DTK_MONTH},    /* "months" relative */
     453             :     {"mons", UNITS, DTK_MONTH}, /* "months" relative */
     454             :     {DMONTH, UNITS, DTK_MONTH}, /* "month" relative */
     455             :     {"months", UNITS, DTK_MONTH},
     456             :     {"ms", UNITS, DTK_MILLISEC},
     457             :     {"msec", UNITS, DTK_MILLISEC},
     458             :     {DMILLISEC, UNITS, DTK_MILLISEC},
     459             :     {"mseconds", UNITS, DTK_MILLISEC},
     460             :     {"msecs", UNITS, DTK_MILLISEC},
     461             :     {"qtr", UNITS, DTK_QUARTER},  /* "quarter" relative */
     462             :     {DQUARTER, UNITS, DTK_QUARTER}, /* "quarter" relative */
     463             :     {"s", UNITS, DTK_SECOND},
     464             :     {"sec", UNITS, DTK_SECOND},
     465             :     {DSECOND, UNITS, DTK_SECOND},
     466             :     {"seconds", UNITS, DTK_SECOND},
     467             :     {"secs", UNITS, DTK_SECOND},
     468             :     {DTIMEZONE, UNITS, DTK_TZ}, /* "timezone" time offset */
     469             :     {"timezone_h", UNITS, DTK_TZ_HOUR}, /* timezone hour units */
     470             :     {"timezone_m", UNITS, DTK_TZ_MINUTE}, /* timezone minutes units */
     471             :     {"us", UNITS, DTK_MICROSEC},  /* "microsecond" relative */
     472             :     {"usec", UNITS, DTK_MICROSEC},    /* "microsecond" relative */
     473             :     {DMICROSEC, UNITS, DTK_MICROSEC},   /* "microsecond" relative */
     474             :     {"useconds", UNITS, DTK_MICROSEC},    /* "microseconds" relative */
     475             :     {"usecs", UNITS, DTK_MICROSEC}, /* "microseconds" relative */
     476             :     {"w", UNITS, DTK_WEEK},       /* "week" relative */
     477             :     {DWEEK, UNITS, DTK_WEEK},   /* "week" relative */
     478             :     {"weeks", UNITS, DTK_WEEK}, /* "weeks" relative */
     479             :     {"y", UNITS, DTK_YEAR},       /* "year" relative */
     480             :     {DYEAR, UNITS, DTK_YEAR},   /* "year" relative */
     481             :     {"years", UNITS, DTK_YEAR}, /* "years" relative */
     482             :     {"yr", UNITS, DTK_YEAR},  /* "year" relative */
     483             :     {"yrs", UNITS, DTK_YEAR}, /* "years" relative */
     484             : };
     485             : 
     486             : static const unsigned int szdatetktbl = lengthof(datetktbl);
     487             : static const unsigned int szdeltatktbl = lengthof(deltatktbl);
     488             : 
     489             : static const datetkn *datecache[MAXDATEFIELDS] = {NULL};
     490             : 
     491             : static const datetkn *deltacache[MAXDATEFIELDS] = {NULL};
     492             : 
     493             : char       *months[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", NULL};
     494             : 
     495             : char       *days[] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", NULL};
     496             : 
     497             : char       *pgtypes_date_weekdays_short[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", NULL};
     498             : 
     499             : char       *pgtypes_date_months[] = {"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December", NULL};
     500             : 
     501             : static const datetkn *
     502         176 : datebsearch(const char *key, const datetkn *base, unsigned int nel)
     503             : {
     504         176 :     if (nel > 0)
     505             :     {
     506         176 :         const datetkn *last = base + nel - 1,
     507             :                    *position;
     508             :         int         result;
     509             : 
     510        1136 :         while (last >= base)
     511             :         {
     512        1116 :             position = base + ((last - base) >> 1);
     513             :             /* precheck the first character for a bit of extra speed */
     514        1116 :             result = (int) key[0] - (int) position->token[0];
     515        1116 :             if (result == 0)
     516             :             {
     517             :                 /* use strncmp so that we match truncated tokens */
     518         536 :                 result = strncmp(key, position->token, TOKMAXLEN);
     519         536 :                 if (result == 0)
     520         156 :                     return position;
     521             :             }
     522         960 :             if (result < 0)
     523         448 :                 last = position - 1;
     524             :             else
     525         512 :                 base = position + 1;
     526             :         }
     527             :     }
     528          20 :     return NULL;
     529             : }
     530             : 
     531             : /* DecodeUnits()
     532             :  * Decode text string using lookup table.
     533             :  * This routine supports time interval decoding.
     534             :  */
     535             : int
     536         176 : DecodeUnits(int field, char *lowtoken, int *val)
     537             : {
     538             :     int         type;
     539             :     const datetkn *tp;
     540             : 
     541             :     /* use strncmp so that we match truncated tokens */
     542         176 :     if (deltacache[field] != NULL &&
     543         120 :         strncmp(lowtoken, deltacache[field]->token, TOKMAXLEN) == 0)
     544          80 :         tp = deltacache[field];
     545             :     else
     546          96 :         tp = datebsearch(lowtoken, deltatktbl, szdeltatktbl);
     547         176 :     deltacache[field] = tp;
     548         176 :     if (tp == NULL)
     549             :     {
     550           4 :         type = UNKNOWN_FIELD;
     551           4 :         *val = 0;
     552             :     }
     553             :     else
     554             :     {
     555         172 :         type = tp->type;
     556         172 :         *val = tp->value;
     557             :     }
     558             : 
     559         176 :     return type;
     560             : }                               /* DecodeUnits() */
     561             : 
     562             : /*
     563             :  * Calendar time to Julian date conversions.
     564             :  * Julian date is commonly used in astronomical applications,
     565             :  *  since it is numerically accurate and computationally simple.
     566             :  * The algorithms here will accurately convert between Julian day
     567             :  *  and calendar date for all non-negative Julian days
     568             :  *  (i.e. from Nov 24, -4713 on).
     569             :  *
     570             :  * These routines will be used by other date/time packages
     571             :  * - thomas 97/02/25
     572             :  *
     573             :  * Rewritten to eliminate overflow problems. This now allows the
     574             :  * routines to work correctly for all Julian day counts from
     575             :  * 0 to 2147483647  (Nov 24, -4713 to Jun 3, 5874898) assuming
     576             :  * a 32-bit integer. Longer types should also work to the limits
     577             :  * of their precision.
     578             :  */
     579             : 
     580             : int
     581        3644 : date2j(int y, int m, int d)
     582             : {
     583             :     int         julian;
     584             :     int         century;
     585             : 
     586        3644 :     if (m > 2)
     587             :     {
     588         208 :         m += 1;
     589         208 :         y += 4800;
     590             :     }
     591             :     else
     592             :     {
     593        3436 :         m += 13;
     594        3436 :         y += 4799;
     595             :     }
     596             : 
     597        3644 :     century = y / 100;
     598        3644 :     julian = y * 365 - 32167;
     599        3644 :     julian += y / 4 - century + century / 4;
     600        3644 :     julian += 7834 * m / 256 + d;
     601             : 
     602        3644 :     return julian;
     603             : }                               /* date2j() */
     604             : 
     605             : void
     606        1136 : j2date(int jd, int *year, int *month, int *day)
     607             : {
     608             :     unsigned int julian;
     609             :     unsigned int quad;
     610             :     unsigned int extra;
     611             :     int         y;
     612             : 
     613        1136 :     julian = jd;
     614        1136 :     julian += 32044;
     615        1136 :     quad = julian / 146097;
     616        1136 :     extra = (julian - quad * 146097) * 4 + 3;
     617        1136 :     julian += 60 + quad * 3 + extra / 146097;
     618        1136 :     quad = julian / 1461;
     619        1136 :     julian -= quad * 1461;
     620        1136 :     y = julian * 4 / 1461;
     621        1136 :     julian = ((y != 0) ? (julian + 305) % 365 : (julian + 306) % 366) + 123;
     622        1136 :     y += quad * 4;
     623        1136 :     *year = y - 4800;
     624        1136 :     quad = julian * 2141 / 65536;
     625        1136 :     *day = julian - 7834 * quad / 256;
     626        1136 :     *month = (quad + 10) % 12 + 1;
     627        1136 : }                               /* j2date() */
     628             : 
     629             : /* DecodeSpecial()
     630             :  * Decode text string using lookup table.
     631             :  * Implement a cache lookup since it is likely that dates
     632             :  *  will be related in format.
     633             :  */
     634             : static int
     635         452 : DecodeSpecial(int field, char *lowtoken, int *val)
     636             : {
     637             :     int         type;
     638             :     const datetkn *tp;
     639             : 
     640             :     /* use strncmp so that we match truncated tokens */
     641         452 :     if (datecache[field] != NULL &&
     642         392 :         strncmp(lowtoken, datecache[field]->token, TOKMAXLEN) == 0)
     643         372 :         tp = datecache[field];
     644             :     else
     645             :     {
     646          80 :         tp = NULL;
     647          80 :         if (!tp)
     648          80 :             tp = datebsearch(lowtoken, datetktbl, szdatetktbl);
     649             :     }
     650         452 :     datecache[field] = tp;
     651         452 :     if (tp == NULL)
     652             :     {
     653          16 :         type = UNKNOWN_FIELD;
     654          16 :         *val = 0;
     655             :     }
     656             :     else
     657             :     {
     658         436 :         type = tp->type;
     659         436 :         *val = tp->value;
     660             :     }
     661             : 
     662         452 :     return type;
     663             : }                               /* DecodeSpecial() */
     664             : 
     665             : /* EncodeDateOnly()
     666             :  * Encode date as local time.
     667             :  */
     668             : void
     669         380 : EncodeDateOnly(struct tm *tm, int style, char *str, bool EuroDates)
     670             : {
     671             :     Assert(tm->tm_mon >= 1 && tm->tm_mon <= MONTHS_PER_YEAR);
     672             : 
     673         380 :     switch (style)
     674             :     {
     675         380 :         case USE_ISO_DATES:
     676             :             /* compatible with ISO date formats */
     677         380 :             if (tm->tm_year > 0)
     678         376 :                 sprintf(str, "%04d-%02d-%02d",
     679             :                         tm->tm_year, tm->tm_mon, tm->tm_mday);
     680             :             else
     681           4 :                 sprintf(str, "%04d-%02d-%02d %s",
     682           4 :                         -(tm->tm_year - 1), tm->tm_mon, tm->tm_mday, "BC");
     683         380 :             break;
     684             : 
     685           0 :         case USE_SQL_DATES:
     686             :             /* compatible with Oracle/Ingres date formats */
     687           0 :             if (EuroDates)
     688           0 :                 sprintf(str, "%02d/%02d", tm->tm_mday, tm->tm_mon);
     689             :             else
     690           0 :                 sprintf(str, "%02d/%02d", tm->tm_mon, tm->tm_mday);
     691           0 :             if (tm->tm_year > 0)
     692           0 :                 sprintf(str + 5, "/%04d", tm->tm_year);
     693             :             else
     694           0 :                 sprintf(str + 5, "/%04d %s", -(tm->tm_year - 1), "BC");
     695           0 :             break;
     696             : 
     697           0 :         case USE_GERMAN_DATES:
     698             :             /* German-style date format */
     699           0 :             sprintf(str, "%02d.%02d", tm->tm_mday, tm->tm_mon);
     700           0 :             if (tm->tm_year > 0)
     701           0 :                 sprintf(str + 5, ".%04d", tm->tm_year);
     702             :             else
     703           0 :                 sprintf(str + 5, ".%04d %s", -(tm->tm_year - 1), "BC");
     704           0 :             break;
     705             : 
     706           0 :         case USE_POSTGRES_DATES:
     707             :         default:
     708             :             /* traditional date-only style for Postgres */
     709           0 :             if (EuroDates)
     710           0 :                 sprintf(str, "%02d-%02d", tm->tm_mday, tm->tm_mon);
     711             :             else
     712           0 :                 sprintf(str, "%02d-%02d", tm->tm_mon, tm->tm_mday);
     713           0 :             if (tm->tm_year > 0)
     714           0 :                 sprintf(str + 5, "-%04d", tm->tm_year);
     715             :             else
     716           0 :                 sprintf(str + 5, "-%04d %s", -(tm->tm_year - 1), "BC");
     717           0 :             break;
     718             :     }
     719         380 : }
     720             : 
     721             : void
     722         136 : TrimTrailingZeros(char *str)
     723             : {
     724         136 :     int         len = strlen(str);
     725             : 
     726             :     /* chop off trailing zeros... but leave at least 2 fractional digits */
     727         340 :     while (*(str + len - 1) == '0' && *(str + len - 3) != '.')
     728             :     {
     729         204 :         len--;
     730         204 :         *(str + len) = '\0';
     731             :     }
     732         136 : }
     733             : 
     734             : /* EncodeDateTime()
     735             :  * Encode date and time interpreted as local time.
     736             :  *
     737             :  * tm and fsec are the value to encode, print_tz determines whether to include
     738             :  * a time zone (the difference between timestamp and timestamptz types), tz is
     739             :  * the numeric time zone offset, tzn is the textual time zone, which if
     740             :  * specified will be used instead of tz by some styles, style is the date
     741             :  * style, str is where to write the output.
     742             :  *
     743             :  * Supported date styles:
     744             :  *  Postgres - day mon hh:mm:ss yyyy tz
     745             :  *  SQL - mm/dd/yyyy hh:mm:ss.ss tz
     746             :  *  ISO - yyyy-mm-dd hh:mm:ss+/-tz
     747             :  *  German - dd.mm.yyyy hh:mm:ss tz
     748             :  * Variants (affects order of month and day for Postgres and SQL styles):
     749             :  *  US - mm/dd/yyyy
     750             :  *  European - dd/mm/yyyy
     751             :  */
     752             : void
     753         632 : EncodeDateTime(struct tm *tm, fsec_t fsec, bool print_tz, int tz, const char *tzn, int style, char *str, bool EuroDates)
     754             : {
     755             :     int         day,
     756             :                 hour,
     757             :                 min;
     758             : 
     759             :     /*
     760             :      * Negative tm_isdst means we have no valid time zone translation.
     761             :      */
     762         632 :     if (tm->tm_isdst < 0)
     763         632 :         print_tz = false;
     764             : 
     765         632 :     switch (style)
     766             :     {
     767         632 :         case USE_ISO_DATES:
     768             :             /* Compatible with ISO-8601 date formats */
     769             : 
     770         632 :             sprintf(str, "%04d-%02d-%02d %02d:%02d",
     771         632 :                     (tm->tm_year > 0) ? tm->tm_year : -(tm->tm_year - 1),
     772             :                     tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min);
     773             : 
     774             :             /*
     775             :              * Print fractional seconds if any.  The field widths here should
     776             :              * be at least equal to MAX_TIMESTAMP_PRECISION.
     777             :              */
     778         632 :             if (fsec != 0)
     779             :             {
     780         136 :                 sprintf(str + strlen(str), ":%02d.%06d", tm->tm_sec, fsec);
     781         136 :                 TrimTrailingZeros(str);
     782             :             }
     783             :             else
     784         496 :                 sprintf(str + strlen(str), ":%02d", tm->tm_sec);
     785             : 
     786         632 :             if (tm->tm_year <= 0)
     787          20 :                 sprintf(str + strlen(str), " BC");
     788             : 
     789         632 :             if (print_tz)
     790             :             {
     791           0 :                 hour = -(tz / SECS_PER_HOUR);
     792           0 :                 min = (abs(tz) / MINS_PER_HOUR) % MINS_PER_HOUR;
     793           0 :                 if (min != 0)
     794           0 :                     sprintf(str + strlen(str), "%+03d:%02d", hour, min);
     795             :                 else
     796           0 :                     sprintf(str + strlen(str), "%+03d", hour);
     797             :             }
     798         632 :             break;
     799             : 
     800           0 :         case USE_SQL_DATES:
     801             :             /* Compatible with Oracle/Ingres date formats */
     802             : 
     803           0 :             if (EuroDates)
     804           0 :                 sprintf(str, "%02d/%02d", tm->tm_mday, tm->tm_mon);
     805             :             else
     806           0 :                 sprintf(str, "%02d/%02d", tm->tm_mon, tm->tm_mday);
     807             : 
     808           0 :             sprintf(str + 5, "/%04d %02d:%02d",
     809           0 :                     (tm->tm_year > 0) ? tm->tm_year : -(tm->tm_year - 1),
     810             :                     tm->tm_hour, tm->tm_min);
     811             : 
     812             :             /*
     813             :              * Print fractional seconds if any.  The field widths here should
     814             :              * be at least equal to MAX_TIMESTAMP_PRECISION.
     815             :              */
     816           0 :             if (fsec != 0)
     817             :             {
     818           0 :                 sprintf(str + strlen(str), ":%02d.%06d", tm->tm_sec, fsec);
     819           0 :                 TrimTrailingZeros(str);
     820             :             }
     821             :             else
     822           0 :                 sprintf(str + strlen(str), ":%02d", tm->tm_sec);
     823             : 
     824           0 :             if (tm->tm_year <= 0)
     825           0 :                 sprintf(str + strlen(str), " BC");
     826             : 
     827             :             /*
     828             :              * Note: the uses of %.*s in this function would be risky if the
     829             :              * timezone names ever contain non-ASCII characters, since we are
     830             :              * not being careful to do encoding-aware clipping.  However, all
     831             :              * TZ abbreviations in the IANA database are plain ASCII.
     832             :              */
     833             : 
     834           0 :             if (print_tz)
     835             :             {
     836           0 :                 if (tzn)
     837           0 :                     sprintf(str + strlen(str), " %.*s", MAXTZLEN, tzn);
     838             :                 else
     839             :                 {
     840           0 :                     hour = -(tz / SECS_PER_HOUR);
     841           0 :                     min = (abs(tz) / MINS_PER_HOUR) % MINS_PER_HOUR;
     842           0 :                     if (min != 0)
     843           0 :                         sprintf(str + strlen(str), "%+03d:%02d", hour, min);
     844             :                     else
     845           0 :                         sprintf(str + strlen(str), "%+03d", hour);
     846             :                 }
     847             :             }
     848           0 :             break;
     849             : 
     850           0 :         case USE_GERMAN_DATES:
     851             :             /* German variant on European style */
     852             : 
     853           0 :             sprintf(str, "%02d.%02d", tm->tm_mday, tm->tm_mon);
     854             : 
     855           0 :             sprintf(str + 5, ".%04d %02d:%02d",
     856           0 :                     (tm->tm_year > 0) ? tm->tm_year : -(tm->tm_year - 1),
     857             :                     tm->tm_hour, tm->tm_min);
     858             : 
     859             :             /*
     860             :              * Print fractional seconds if any.  The field widths here should
     861             :              * be at least equal to MAX_TIMESTAMP_PRECISION.
     862             :              */
     863           0 :             if (fsec != 0)
     864             :             {
     865           0 :                 sprintf(str + strlen(str), ":%02d.%06d", tm->tm_sec, fsec);
     866           0 :                 TrimTrailingZeros(str);
     867             :             }
     868             :             else
     869           0 :                 sprintf(str + strlen(str), ":%02d", tm->tm_sec);
     870             : 
     871           0 :             if (tm->tm_year <= 0)
     872           0 :                 sprintf(str + strlen(str), " BC");
     873             : 
     874           0 :             if (print_tz)
     875             :             {
     876           0 :                 if (tzn)
     877           0 :                     sprintf(str + strlen(str), " %.*s", MAXTZLEN, tzn);
     878             :                 else
     879             :                 {
     880           0 :                     hour = -(tz / SECS_PER_HOUR);
     881           0 :                     min = (abs(tz) / MINS_PER_HOUR) % MINS_PER_HOUR;
     882           0 :                     if (min != 0)
     883           0 :                         sprintf(str + strlen(str), "%+03d:%02d", hour, min);
     884             :                     else
     885           0 :                         sprintf(str + strlen(str), "%+03d", hour);
     886             :                 }
     887             :             }
     888           0 :             break;
     889             : 
     890           0 :         case USE_POSTGRES_DATES:
     891             :         default:
     892             :             /* Backward-compatible with traditional Postgres abstime dates */
     893             : 
     894           0 :             day = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday);
     895           0 :             tm->tm_wday = (int) ((day + date2j(2000, 1, 1) + 1) % 7);
     896             : 
     897           0 :             memcpy(str, days[tm->tm_wday], 3);
     898           0 :             strcpy(str + 3, " ");
     899             : 
     900           0 :             if (EuroDates)
     901           0 :                 sprintf(str + 4, "%02d %3s", tm->tm_mday, months[tm->tm_mon - 1]);
     902             :             else
     903           0 :                 sprintf(str + 4, "%3s %02d", months[tm->tm_mon - 1], tm->tm_mday);
     904             : 
     905           0 :             sprintf(str + 10, " %02d:%02d", tm->tm_hour, tm->tm_min);
     906             : 
     907             :             /*
     908             :              * Print fractional seconds if any.  The field widths here should
     909             :              * be at least equal to MAX_TIMESTAMP_PRECISION.
     910             :              */
     911           0 :             if (fsec != 0)
     912             :             {
     913           0 :                 sprintf(str + strlen(str), ":%02d.%06d", tm->tm_sec, fsec);
     914           0 :                 TrimTrailingZeros(str);
     915             :             }
     916             :             else
     917           0 :                 sprintf(str + strlen(str), ":%02d", tm->tm_sec);
     918             : 
     919           0 :             sprintf(str + strlen(str), " %04d",
     920           0 :                     (tm->tm_year > 0) ? tm->tm_year : -(tm->tm_year - 1));
     921           0 :             if (tm->tm_year <= 0)
     922           0 :                 sprintf(str + strlen(str), " BC");
     923             : 
     924           0 :             if (print_tz)
     925             :             {
     926           0 :                 if (tzn)
     927           0 :                     sprintf(str + strlen(str), " %.*s", MAXTZLEN, tzn);
     928             :                 else
     929             :                 {
     930             :                     /*
     931             :                      * We have a time zone, but no string version. Use the
     932             :                      * numeric form, but be sure to include a leading space to
     933             :                      * avoid formatting something which would be rejected by
     934             :                      * the date/time parser later. - thomas 2001-10-19
     935             :                      */
     936           0 :                     hour = -(tz / SECS_PER_HOUR);
     937           0 :                     min = (abs(tz) / MINS_PER_HOUR) % MINS_PER_HOUR;
     938           0 :                     if (min != 0)
     939           0 :                         sprintf(str + strlen(str), " %+03d:%02d", hour, min);
     940             :                     else
     941           0 :                         sprintf(str + strlen(str), " %+03d", hour);
     942             :                 }
     943             :             }
     944           0 :             break;
     945             :     }
     946         632 : }
     947             : 
     948             : int
     949           0 : GetEpochTime(struct tm *tm)
     950             : {
     951             :     struct tm  *t0;
     952           0 :     time_t      epoch = 0;
     953             : 
     954           0 :     t0 = gmtime(&epoch);
     955             : 
     956           0 :     if (t0)
     957             :     {
     958           0 :         tm->tm_year = t0->tm_year + 1900;
     959           0 :         tm->tm_mon = t0->tm_mon + 1;
     960           0 :         tm->tm_mday = t0->tm_mday;
     961           0 :         tm->tm_hour = t0->tm_hour;
     962           0 :         tm->tm_min = t0->tm_min;
     963           0 :         tm->tm_sec = t0->tm_sec;
     964             : 
     965           0 :         return 0;
     966             :     }
     967             : 
     968           0 :     return -1;
     969             : }                               /* GetEpochTime() */
     970             : 
     971             : static void
     972           4 : abstime2tm(AbsoluteTime _time, int *tzp, struct tm *tm, char **tzn)
     973             : {
     974           4 :     time_t      time = (time_t) _time;
     975             :     struct tm  *tx;
     976             : 
     977           4 :     errno = 0;
     978           4 :     if (tzp != NULL)
     979           4 :         tx = localtime((time_t *) &time);
     980             :     else
     981           0 :         tx = gmtime((time_t *) &time);
     982             : 
     983           4 :     if (!tx)
     984             :     {
     985           0 :         errno = PGTYPES_TS_BAD_TIMESTAMP;
     986           0 :         return;
     987             :     }
     988             : 
     989           4 :     tm->tm_year = tx->tm_year + 1900;
     990           4 :     tm->tm_mon = tx->tm_mon + 1;
     991           4 :     tm->tm_mday = tx->tm_mday;
     992           4 :     tm->tm_hour = tx->tm_hour;
     993           4 :     tm->tm_min = tx->tm_min;
     994           4 :     tm->tm_sec = tx->tm_sec;
     995           4 :     tm->tm_isdst = tx->tm_isdst;
     996             : 
     997             : #if defined(HAVE_STRUCT_TM_TM_ZONE)
     998           4 :     tm->tm_gmtoff = tx->tm_gmtoff;
     999           4 :     tm->tm_zone = tx->tm_zone;
    1000             : 
    1001           4 :     if (tzp != NULL)
    1002             :     {
    1003             :         /*
    1004             :          * We have a brute force time zone per SQL99? Then use it without
    1005             :          * change since we have already rotated to the time zone.
    1006             :          */
    1007           4 :         *tzp = -tm->tm_gmtoff;   /* tm_gmtoff is Sun/DEC-ism */
    1008             : 
    1009             :         /*
    1010             :          * FreeBSD man pages indicate that this should work - tgl 97/04/23
    1011             :          */
    1012           4 :         if (tzn != NULL)
    1013             :         {
    1014             :             /*
    1015             :              * Copy no more than MAXTZLEN bytes of timezone to tzn, in case it
    1016             :              * contains an error message, which doesn't fit in the buffer
    1017             :              */
    1018           0 :             strlcpy(*tzn, tm->tm_zone, MAXTZLEN + 1);
    1019           0 :             if (strlen(tm->tm_zone) > MAXTZLEN)
    1020           0 :                 tm->tm_isdst = -1;
    1021             :         }
    1022             :     }
    1023             :     else
    1024           0 :         tm->tm_isdst = -1;
    1025             : #elif defined(HAVE_INT_TIMEZONE)
    1026             :     if (tzp != NULL)
    1027             :     {
    1028             :         *tzp = (tm->tm_isdst > 0) ? TIMEZONE_GLOBAL - SECS_PER_HOUR : TIMEZONE_GLOBAL;
    1029             : 
    1030             :         if (tzn != NULL)
    1031             :         {
    1032             :             /*
    1033             :              * Copy no more than MAXTZLEN bytes of timezone to tzn, in case it
    1034             :              * contains an error message, which doesn't fit in the buffer
    1035             :              */
    1036             :             strlcpy(*tzn, TZNAME_GLOBAL[tm->tm_isdst], MAXTZLEN + 1);
    1037             :             if (strlen(TZNAME_GLOBAL[tm->tm_isdst]) > MAXTZLEN)
    1038             :                 tm->tm_isdst = -1;
    1039             :         }
    1040             :     }
    1041             :     else
    1042             :         tm->tm_isdst = -1;
    1043             : #else                           /* not (HAVE_STRUCT_TM_TM_ZONE ||
    1044             :                                  * HAVE_INT_TIMEZONE) */
    1045             :     if (tzp != NULL)
    1046             :     {
    1047             :         /* default to UTC */
    1048             :         *tzp = 0;
    1049             :         if (tzn != NULL)
    1050             :             *tzn = NULL;
    1051             :     }
    1052             :     else
    1053             :         tm->tm_isdst = -1;
    1054             : #endif
    1055             : }
    1056             : 
    1057             : void
    1058           4 : GetCurrentDateTime(struct tm *tm)
    1059             : {
    1060             :     int         tz;
    1061             : 
    1062           4 :     abstime2tm(time(NULL), &tz, tm, NULL);
    1063           4 : }
    1064             : 
    1065             : void
    1066         652 : dt2time(double jd, int *hour, int *min, int *sec, fsec_t *fsec)
    1067             : {
    1068             :     int64       time;
    1069             : 
    1070         652 :     time = jd;
    1071         652 :     *hour = time / USECS_PER_HOUR;
    1072         652 :     time -= (*hour) * USECS_PER_HOUR;
    1073         652 :     *min = time / USECS_PER_MINUTE;
    1074         652 :     time -= (*min) * USECS_PER_MINUTE;
    1075         652 :     *sec = time / USECS_PER_SEC;
    1076         652 :     *fsec = time - (*sec * USECS_PER_SEC);
    1077         652 : }                               /* dt2time() */
    1078             : 
    1079             : 
    1080             : 
    1081             : /* DecodeNumberField()
    1082             :  * Interpret numeric string as a concatenated date or time field.
    1083             :  * Use the context of previously decoded fields to help with
    1084             :  * the interpretation.
    1085             :  */
    1086             : static int
    1087          56 : DecodeNumberField(int len, char *str, int fmask,
    1088             :                   int *tmask, struct tm *tm, fsec_t *fsec, bool *is2digits)
    1089             : {
    1090             :     char       *cp;
    1091             : 
    1092             :     /*
    1093             :      * Have a decimal point? Then this is a date or something with a seconds
    1094             :      * field...
    1095             :      */
    1096          56 :     if ((cp = strchr(str, '.')) != NULL)
    1097             :     {
    1098             :         char        fstr[7];
    1099             :         int         i;
    1100             : 
    1101           0 :         cp++;
    1102             : 
    1103             :         /*
    1104             :          * OK, we have at most six digits to care about. Let's construct a
    1105             :          * string with those digits, zero-padded on the right, and then do the
    1106             :          * conversion to an integer.
    1107             :          *
    1108             :          * XXX This truncates the seventh digit, unlike rounding it as the
    1109             :          * backend does.
    1110             :          */
    1111           0 :         for (i = 0; i < 6; i++)
    1112           0 :             fstr[i] = *cp != '\0' ? *cp++ : '0';
    1113           0 :         fstr[i] = '\0';
    1114           0 :         *fsec = strtoint(fstr, NULL, 10);
    1115           0 :         *cp = '\0';
    1116           0 :         len = strlen(str);
    1117             :     }
    1118             :     /* No decimal point and no complete date yet? */
    1119          56 :     else if ((fmask & DTK_DATE_M) != DTK_DATE_M)
    1120             :     {
    1121             :         /* yyyymmdd? */
    1122          56 :         if (len == 8)
    1123             :         {
    1124          32 :             *tmask = DTK_DATE_M;
    1125             : 
    1126          32 :             tm->tm_mday = atoi(str + 6);
    1127          32 :             *(str + 6) = '\0';
    1128          32 :             tm->tm_mon = atoi(str + 4);
    1129          32 :             *(str + 4) = '\0';
    1130          32 :             tm->tm_year = atoi(str + 0);
    1131             : 
    1132          32 :             return DTK_DATE;
    1133             :         }
    1134             :         /* yymmdd? */
    1135          24 :         else if (len == 6)
    1136             :         {
    1137          24 :             *tmask = DTK_DATE_M;
    1138          24 :             tm->tm_mday = atoi(str + 4);
    1139          24 :             *(str + 4) = '\0';
    1140          24 :             tm->tm_mon = atoi(str + 2);
    1141          24 :             *(str + 2) = '\0';
    1142          24 :             tm->tm_year = atoi(str + 0);
    1143          24 :             *is2digits = true;
    1144             : 
    1145          24 :             return DTK_DATE;
    1146             :         }
    1147             :         /* yyddd? */
    1148           0 :         else if (len == 5)
    1149             :         {
    1150           0 :             *tmask = DTK_DATE_M;
    1151           0 :             tm->tm_mday = atoi(str + 2);
    1152           0 :             *(str + 2) = '\0';
    1153           0 :             tm->tm_mon = 1;
    1154           0 :             tm->tm_year = atoi(str + 0);
    1155           0 :             *is2digits = true;
    1156             : 
    1157           0 :             return DTK_DATE;
    1158             :         }
    1159             :     }
    1160             : 
    1161             :     /* not all time fields are specified? */
    1162           0 :     if ((fmask & DTK_TIME_M) != DTK_TIME_M)
    1163             :     {
    1164             :         /* hhmmss */
    1165           0 :         if (len == 6)
    1166             :         {
    1167           0 :             *tmask = DTK_TIME_M;
    1168           0 :             tm->tm_sec = atoi(str + 4);
    1169           0 :             *(str + 4) = '\0';
    1170           0 :             tm->tm_min = atoi(str + 2);
    1171           0 :             *(str + 2) = '\0';
    1172           0 :             tm->tm_hour = atoi(str + 0);
    1173             : 
    1174           0 :             return DTK_TIME;
    1175             :         }
    1176             :         /* hhmm? */
    1177           0 :         else if (len == 4)
    1178             :         {
    1179           0 :             *tmask = DTK_TIME_M;
    1180           0 :             tm->tm_sec = 0;
    1181           0 :             tm->tm_min = atoi(str + 2);
    1182           0 :             *(str + 2) = '\0';
    1183           0 :             tm->tm_hour = atoi(str + 0);
    1184             : 
    1185           0 :             return DTK_TIME;
    1186             :         }
    1187             :     }
    1188             : 
    1189           0 :     return -1;
    1190             : }                               /* DecodeNumberField() */
    1191             : 
    1192             : 
    1193             : /* DecodeNumber()
    1194             :  * Interpret plain numeric field as a date value in context.
    1195             :  */
    1196             : static int
    1197        1592 : DecodeNumber(int flen, char *str, int fmask,
    1198             :              int *tmask, struct tm *tm, fsec_t *fsec, bool *is2digits, bool EuroDates)
    1199             : {
    1200             :     int         val;
    1201             :     char       *cp;
    1202             : 
    1203        1592 :     *tmask = 0;
    1204             : 
    1205        1592 :     val = strtoint(str, &cp, 10);
    1206        1592 :     if (cp == str)
    1207           0 :         return -1;
    1208             : 
    1209        1592 :     if (*cp == '.')
    1210             :     {
    1211             :         /*
    1212             :          * More than two digits? Then could be a date or a run-together time:
    1213             :          * 2001.360 20011225 040506.789
    1214             :          */
    1215           0 :         if (cp - str > 2)
    1216           0 :             return DecodeNumberField(flen, str, (fmask | DTK_DATE_M),
    1217             :                                      tmask, tm, fsec, is2digits);
    1218             : 
    1219           0 :         *fsec = strtod(cp, &cp);
    1220           0 :         if (*cp != '\0')
    1221           0 :             return -1;
    1222             :     }
    1223        1592 :     else if (*cp != '\0')
    1224           0 :         return -1;
    1225             : 
    1226             :     /* Special case day of year? */
    1227        1592 :     if (flen == 3 && (fmask & DTK_M(YEAR)) && val >= 1 && val <= 366)
    1228             :     {
    1229          24 :         *tmask = (DTK_M(DOY) | DTK_M(MONTH) | DTK_M(DAY));
    1230          24 :         tm->tm_yday = val;
    1231          24 :         j2date(date2j(tm->tm_year, 1, 1) + tm->tm_yday - 1,
    1232             :                &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
    1233             :     }
    1234             : 
    1235             :     /***
    1236             :      * Enough digits to be unequivocal year? Used to test for 4 digits or
    1237             :      * more, but we now test first for a three-digit doy so anything
    1238             :      * bigger than two digits had better be an explicit year.
    1239             :      * - thomas 1999-01-09
    1240             :      * Back to requiring a 4 digit year. We accept a two digit
    1241             :      * year farther down. - thomas 2000-03-28
    1242             :      ***/
    1243        1568 :     else if (flen >= 4)
    1244             :     {
    1245         480 :         *tmask = DTK_M(YEAR);
    1246             : 
    1247             :         /* already have a year? then see if we can substitute... */
    1248         480 :         if ((fmask & DTK_M(YEAR)) && !(fmask & DTK_M(DAY)) &&
    1249           0 :             tm->tm_year >= 1 && tm->tm_year <= 31)
    1250             :         {
    1251           0 :             tm->tm_mday = tm->tm_year;
    1252           0 :             *tmask = DTK_M(DAY);
    1253             :         }
    1254             : 
    1255         480 :         tm->tm_year = val;
    1256             :     }
    1257             : 
    1258             :     /* already have year? then could be month */
    1259        1088 :     else if ((fmask & DTK_M(YEAR)) && !(fmask & DTK_M(MONTH)) && val >= 1 && val <= MONTHS_PER_YEAR)
    1260             :     {
    1261         224 :         *tmask = DTK_M(MONTH);
    1262         224 :         tm->tm_mon = val;
    1263             :     }
    1264             :     /* no year and EuroDates enabled? then could be day */
    1265         864 :     else if ((EuroDates || (fmask & DTK_M(MONTH))) &&
    1266         740 :              !(fmask & DTK_M(YEAR)) && !(fmask & DTK_M(DAY)) &&
    1267         348 :              val >= 1 && val <= 31)
    1268             :     {
    1269         324 :         *tmask = DTK_M(DAY);
    1270         324 :         tm->tm_mday = val;
    1271             :     }
    1272         540 :     else if (!(fmask & DTK_M(MONTH)) && val >= 1 && val <= MONTHS_PER_YEAR)
    1273             :     {
    1274         120 :         *tmask = DTK_M(MONTH);
    1275         120 :         tm->tm_mon = val;
    1276             :     }
    1277         420 :     else if (!(fmask & DTK_M(DAY)) && val >= 1 && val <= 31)
    1278             :     {
    1279         272 :         *tmask = DTK_M(DAY);
    1280         272 :         tm->tm_mday = val;
    1281             :     }
    1282             : 
    1283             :     /*
    1284             :      * Check for 2 or 4 or more digits, but currently we reach here only if
    1285             :      * two digits. - thomas 2000-03-28
    1286             :      */
    1287         148 :     else if (!(fmask & DTK_M(YEAR)) && (flen >= 4 || flen == 2))
    1288             :     {
    1289         148 :         *tmask = DTK_M(YEAR);
    1290         148 :         tm->tm_year = val;
    1291             : 
    1292             :         /* adjust ONLY if exactly two digits... */
    1293         148 :         *is2digits = (flen == 2);
    1294             :     }
    1295             :     else
    1296           0 :         return -1;
    1297             : 
    1298        1592 :     return 0;
    1299             : }                               /* DecodeNumber() */
    1300             : 
    1301             : /* DecodeDate()
    1302             :  * Decode date string which includes delimiters.
    1303             :  * Insist on a complete set of fields.
    1304             :  */
    1305             : static int
    1306         532 : DecodeDate(char *str, int fmask, int *tmask, struct tm *tm, bool EuroDates)
    1307             : {
    1308             :     fsec_t      fsec;
    1309             : 
    1310         532 :     int         nf = 0;
    1311             :     int         i,
    1312             :                 len;
    1313         532 :     bool        bc = false;
    1314         532 :     bool        is2digits = false;
    1315             :     int         type,
    1316             :                 val,
    1317         532 :                 dmask = 0;
    1318             :     char       *field[MAXDATEFIELDS];
    1319             : 
    1320             :     /* parse this string... */
    1321        2096 :     while (*str != '\0' && nf < MAXDATEFIELDS)
    1322             :     {
    1323             :         /* skip field separators */
    1324        1756 :         while (!isalnum((unsigned char) *str))
    1325         192 :             str++;
    1326             : 
    1327        1564 :         field[nf] = str;
    1328        1564 :         if (isdigit((unsigned char) *str))
    1329             :         {
    1330        4812 :             while (isdigit((unsigned char) *str))
    1331        3420 :                 str++;
    1332             :         }
    1333         172 :         else if (isalpha((unsigned char) *str))
    1334             :         {
    1335        1092 :             while (isalpha((unsigned char) *str))
    1336         920 :                 str++;
    1337             :         }
    1338             : 
    1339             :         /* Just get rid of any non-digit, non-alpha characters... */
    1340        1564 :         if (*str != '\0')
    1341        1032 :             *str++ = '\0';
    1342        1564 :         nf++;
    1343             :     }
    1344             : 
    1345             : #if 0
    1346             :     /* don't allow too many fields */
    1347             :     if (nf > 3)
    1348             :         return -1;
    1349             : #endif
    1350             : 
    1351         532 :     *tmask = 0;
    1352             : 
    1353             :     /* look first for text fields, since that will be unambiguous month */
    1354        2092 :     for (i = 0; i < nf; i++)
    1355             :     {
    1356        1564 :         if (isalpha((unsigned char) *field[i]))
    1357             :         {
    1358         172 :             type = DecodeSpecial(i, field[i], &val);
    1359         172 :             if (type == IGNORE_DTF)
    1360           0 :                 continue;
    1361             : 
    1362         172 :             dmask = DTK_M(type);
    1363         172 :             switch (type)
    1364             :             {
    1365         168 :                 case MONTH:
    1366         168 :                     tm->tm_mon = val;
    1367         168 :                     break;
    1368             : 
    1369           0 :                 case ADBC:
    1370           0 :                     bc = (val == BC);
    1371           0 :                     break;
    1372             : 
    1373           4 :                 default:
    1374           4 :                     return -1;
    1375             :             }
    1376         168 :             if (fmask & dmask)
    1377           0 :                 return -1;
    1378             : 
    1379         168 :             fmask |= dmask;
    1380         168 :             *tmask |= dmask;
    1381             : 
    1382             :             /* mark this field as being completed */
    1383         168 :             field[i] = NULL;
    1384             :         }
    1385             :     }
    1386             : 
    1387             :     /* now pick up remaining numeric fields */
    1388        2088 :     for (i = 0; i < nf; i++)
    1389             :     {
    1390        1560 :         if (field[i] == NULL)
    1391         168 :             continue;
    1392             : 
    1393        1392 :         if ((len = strlen(field[i])) <= 0)
    1394           0 :             return -1;
    1395             : 
    1396        1392 :         if (DecodeNumber(len, field[i], fmask, &dmask, tm, &fsec, &is2digits, EuroDates) != 0)
    1397           0 :             return -1;
    1398             : 
    1399        1392 :         if (fmask & dmask)
    1400           0 :             return -1;
    1401             : 
    1402        1392 :         fmask |= dmask;
    1403        1392 :         *tmask |= dmask;
    1404             :     }
    1405             : 
    1406         528 :     if ((fmask & ~(DTK_M(DOY) | DTK_M(TZ))) != DTK_DATE_M)
    1407           0 :         return -1;
    1408             : 
    1409             :     /* there is no year zero in AD/BC notation; i.e. "1 BC" == year 0 */
    1410         528 :     if (bc)
    1411             :     {
    1412           0 :         if (tm->tm_year > 0)
    1413           0 :             tm->tm_year = -(tm->tm_year - 1);
    1414             :         else
    1415           0 :             return -1;
    1416             :     }
    1417         528 :     else if (is2digits)
    1418             :     {
    1419         124 :         if (tm->tm_year < 70)
    1420          48 :             tm->tm_year += 2000;
    1421          76 :         else if (tm->tm_year < 100)
    1422          76 :             tm->tm_year += 1900;
    1423             :     }
    1424             : 
    1425         528 :     return 0;
    1426             : }                               /* DecodeDate() */
    1427             : 
    1428             : 
    1429             : /* DecodeTime()
    1430             :  * Decode time string which includes delimiters.
    1431             :  * Only check the lower limit on hours, since this same code
    1432             :  *  can be used to represent time spans.
    1433             :  */
    1434             : int
    1435         500 : DecodeTime(char *str, int *tmask, struct tm *tm, fsec_t *fsec)
    1436             : {
    1437             :     char       *cp;
    1438             : 
    1439         500 :     *tmask = DTK_TIME_M;
    1440             : 
    1441         500 :     tm->tm_hour = strtoint(str, &cp, 10);
    1442         500 :     if (*cp != ':')
    1443           0 :         return -1;
    1444         500 :     str = cp + 1;
    1445         500 :     tm->tm_min = strtoint(str, &cp, 10);
    1446         500 :     if (*cp == '\0')
    1447             :     {
    1448         136 :         tm->tm_sec = 0;
    1449         136 :         *fsec = 0;
    1450             :     }
    1451         364 :     else if (*cp != ':')
    1452           0 :         return -1;
    1453             :     else
    1454             :     {
    1455         364 :         str = cp + 1;
    1456         364 :         tm->tm_sec = strtoint(str, &cp, 10);
    1457         364 :         if (*cp == '\0')
    1458         228 :             *fsec = 0;
    1459         136 :         else if (*cp == '.')
    1460             :         {
    1461             :             char        fstr[7];
    1462             :             int         i;
    1463             : 
    1464         136 :             cp++;
    1465             : 
    1466             :             /*
    1467             :              * OK, we have at most six digits to care about. Let's construct a
    1468             :              * string with those digits, zero-padded on the right, and then do
    1469             :              * the conversion to an integer.
    1470             :              *
    1471             :              * XXX This truncates the seventh digit, unlike rounding it as the
    1472             :              * backend does.
    1473             :              */
    1474         952 :             for (i = 0; i < 6; i++)
    1475         816 :                 fstr[i] = *cp != '\0' ? *cp++ : '0';
    1476         136 :             fstr[i] = '\0';
    1477         136 :             *fsec = strtoint(fstr, &cp, 10);
    1478         136 :             if (*cp != '\0')
    1479           0 :                 return -1;
    1480             :         }
    1481             :         else
    1482           0 :             return -1;
    1483             :     }
    1484             : 
    1485             :     /* do a sanity check */
    1486         500 :     if (tm->tm_hour < 0 || tm->tm_min < 0 || tm->tm_min > 59 ||
    1487         500 :         tm->tm_sec < 0 || tm->tm_sec > 59 || *fsec >= USECS_PER_SEC)
    1488           0 :         return -1;
    1489             : 
    1490         500 :     return 0;
    1491             : }                               /* DecodeTime() */
    1492             : 
    1493             : /* DecodeTimezone()
    1494             :  * Interpret string as a numeric timezone.
    1495             :  *
    1496             :  * Note: we allow timezone offsets up to 13:59.  There are places that
    1497             :  * use +1300 summer time.
    1498             :  */
    1499             : static int
    1500         236 : DecodeTimezone(char *str, int *tzp)
    1501             : {
    1502             :     int         tz;
    1503             :     int         hr,
    1504             :                 min;
    1505             :     char       *cp;
    1506             :     int         len;
    1507             : 
    1508             :     /* assume leading character is "+" or "-" */
    1509         236 :     hr = strtoint(str + 1, &cp, 10);
    1510             : 
    1511             :     /* explicit delimiter? */
    1512         236 :     if (*cp == ':')
    1513          68 :         min = strtoint(cp + 1, &cp, 10);
    1514             :     /* otherwise, might have run things together... */
    1515         168 :     else if (*cp == '\0' && (len = strlen(str)) > 3)
    1516             :     {
    1517          32 :         min = strtoint(str + len - 2, &cp, 10);
    1518          32 :         if (min < 0 || min >= 60)
    1519           0 :             return -1;
    1520             : 
    1521          32 :         *(str + len - 2) = '\0';
    1522          32 :         hr = strtoint(str + 1, &cp, 10);
    1523          32 :         if (hr < 0 || hr > 13)
    1524           0 :             return -1;
    1525             :     }
    1526             :     else
    1527         136 :         min = 0;
    1528             : 
    1529         236 :     tz = (hr * MINS_PER_HOUR + min) * SECS_PER_MINUTE;
    1530         236 :     if (*str == '-')
    1531          68 :         tz = -tz;
    1532             : 
    1533         236 :     *tzp = -tz;
    1534         236 :     return *cp != '\0';
    1535             : }                               /* DecodeTimezone() */
    1536             : 
    1537             : 
    1538             : /* DecodePosixTimezone()
    1539             :  * Interpret string as a POSIX-compatible timezone:
    1540             :  *  PST-hh:mm
    1541             :  *  PST+h
    1542             :  * - thomas 2000-03-15
    1543             :  */
    1544             : static int
    1545           0 : DecodePosixTimezone(char *str, int *tzp)
    1546             : {
    1547             :     int         val,
    1548             :                 tz;
    1549             :     int         type;
    1550             :     char       *cp;
    1551             :     char        delim;
    1552             : 
    1553           0 :     cp = str;
    1554           0 :     while (*cp != '\0' && isalpha((unsigned char) *cp))
    1555           0 :         cp++;
    1556             : 
    1557           0 :     if (DecodeTimezone(cp, &tz) != 0)
    1558           0 :         return -1;
    1559             : 
    1560           0 :     delim = *cp;
    1561           0 :     *cp = '\0';
    1562           0 :     type = DecodeSpecial(MAXDATEFIELDS - 1, str, &val);
    1563           0 :     *cp = delim;
    1564             : 
    1565           0 :     switch (type)
    1566             :     {
    1567           0 :         case DTZ:
    1568             :         case TZ:
    1569           0 :             *tzp = -(val + tz);
    1570           0 :             break;
    1571             : 
    1572           0 :         default:
    1573           0 :             return -1;
    1574             :     }
    1575             : 
    1576           0 :     return 0;
    1577             : }                               /* DecodePosixTimezone() */
    1578             : 
    1579             : /* ParseDateTime()
    1580             :  * Break string into tokens based on a date/time context.
    1581             :  * Several field types are assigned:
    1582             :  *  DTK_NUMBER - digits and (possibly) a decimal point
    1583             :  *  DTK_DATE - digits and two delimiters, or digits and text
    1584             :  *  DTK_TIME - digits, colon delimiters, and possibly a decimal point
    1585             :  *  DTK_STRING - text (no digits)
    1586             :  *  DTK_SPECIAL - leading "+" or "-" followed by text
    1587             :  *  DTK_TZ - leading "+" or "-" followed by digits
    1588             :  * Note that some field types can hold unexpected items:
    1589             :  *  DTK_NUMBER can hold date fields (yy.ddd)
    1590             :  *  DTK_STRING can hold months (January) and time zones (PST)
    1591             :  *  DTK_DATE can hold Posix time zones (GMT-8)
    1592             :  *
    1593             :  * The "lowstr" work buffer must have at least strlen(timestr) + MAXDATEFIELDS
    1594             :  * bytes of space.  On output, field[] entries will point into it.
    1595             :  * The field[] and ftype[] arrays must have at least MAXDATEFIELDS entries.
    1596             :  */
    1597             : int
    1598         832 : ParseDateTime(char *timestr, char *lowstr,
    1599             :               char **field, int *ftype, int *numfields, char **endstr)
    1600             : {
    1601         832 :     int         nf = 0;
    1602         832 :     char       *lp = lowstr;
    1603             : 
    1604         832 :     *endstr = timestr;
    1605             :     /* outer loop through fields */
    1606        4536 :     while (*(*endstr) != '\0')
    1607             :     {
    1608             :         /* Record start of current field */
    1609        3708 :         if (nf >= MAXDATEFIELDS)
    1610           4 :             return -1;
    1611        3704 :         field[nf] = lp;
    1612             : 
    1613             :         /* leading digit? then date or time */
    1614        3704 :         if (isdigit((unsigned char) *(*endstr)))
    1615             :         {
    1616        1444 :             *lp++ = *(*endstr)++;
    1617        3712 :             while (isdigit((unsigned char) *(*endstr)))
    1618        2268 :                 *lp++ = *(*endstr)++;
    1619             : 
    1620             :             /* time field? */
    1621        1444 :             if (*(*endstr) == ':')
    1622             :             {
    1623         500 :                 ftype[nf] = DTK_TIME;
    1624         500 :                 *lp++ = *(*endstr)++;
    1625        3544 :                 while (isdigit((unsigned char) *(*endstr)) ||
    1626        1000 :                        (*(*endstr) == ':') || (*(*endstr) == '.'))
    1627        3044 :                     *lp++ = *(*endstr)++;
    1628             :             }
    1629             :             /* date field? allow embedded text month */
    1630         944 :             else if (*(*endstr) == '-' || *(*endstr) == '/' || *(*endstr) == '.')
    1631         480 :             {
    1632             :                 /* save delimiting character to use later */
    1633         480 :                 char       *dp = (*endstr);
    1634             : 
    1635         480 :                 *lp++ = *(*endstr)++;
    1636             :                 /* second field is all digits? then no embedded text month */
    1637         480 :                 if (isdigit((unsigned char) *(*endstr)))
    1638             :                 {
    1639         360 :                     ftype[nf] = (*dp == '.') ? DTK_NUMBER : DTK_DATE;
    1640         996 :                     while (isdigit((unsigned char) *(*endstr)))
    1641         636 :                         *lp++ = *(*endstr)++;
    1642             : 
    1643             :                     /*
    1644             :                      * insist that the delimiters match to get a three-field
    1645             :                      * date.
    1646             :                      */
    1647         360 :                     if (*(*endstr) == *dp)
    1648             :                     {
    1649         336 :                         ftype[nf] = DTK_DATE;
    1650         336 :                         *lp++ = *(*endstr)++;
    1651        1144 :                         while (isdigit((unsigned char) *(*endstr)) || (*(*endstr) == *dp))
    1652         808 :                             *lp++ = *(*endstr)++;
    1653             :                     }
    1654             :                 }
    1655             :                 else
    1656             :                 {
    1657         120 :                     ftype[nf] = DTK_DATE;
    1658         888 :                     while (isalnum((unsigned char) *(*endstr)) || (*(*endstr) == *dp))
    1659         768 :                         *lp++ = pg_tolower((unsigned char) *(*endstr)++);
    1660             :                 }
    1661             :             }
    1662             : 
    1663             :             /*
    1664             :              * otherwise, number only and will determine year, month, day, or
    1665             :              * concatenated fields later...
    1666             :              */
    1667             :             else
    1668         464 :                 ftype[nf] = DTK_NUMBER;
    1669             :         }
    1670             :         /* Leading decimal point? Then fractional seconds... */
    1671        2260 :         else if (*(*endstr) == '.')
    1672             :         {
    1673         196 :             *lp++ = *(*endstr)++;
    1674         196 :             while (isdigit((unsigned char) *(*endstr)))
    1675           0 :                 *lp++ = *(*endstr)++;
    1676             : 
    1677         196 :             ftype[nf] = DTK_NUMBER;
    1678             :         }
    1679             : 
    1680             :         /*
    1681             :          * text? then date string, month, day of week, special, or timezone
    1682             :          */
    1683        2064 :         else if (isalpha((unsigned char) *(*endstr)))
    1684             :         {
    1685         516 :             ftype[nf] = DTK_STRING;
    1686         516 :             *lp++ = pg_tolower((unsigned char) *(*endstr)++);
    1687        2476 :             while (isalpha((unsigned char) *(*endstr)))
    1688        1960 :                 *lp++ = pg_tolower((unsigned char) *(*endstr)++);
    1689             : 
    1690             :             /*
    1691             :              * Full date string with leading text month? Could also be a POSIX
    1692             :              * time zone...
    1693             :              */
    1694         516 :             if (*(*endstr) == '-' || *(*endstr) == '/' || *(*endstr) == '.')
    1695             :             {
    1696          48 :                 char       *dp = (*endstr);
    1697             : 
    1698          48 :                 ftype[nf] = DTK_DATE;
    1699          48 :                 *lp++ = *(*endstr)++;
    1700         336 :                 while (isdigit((unsigned char) *(*endstr)) || *(*endstr) == *dp)
    1701         288 :                     *lp++ = *(*endstr)++;
    1702             :             }
    1703             :         }
    1704             :         /* skip leading spaces */
    1705        1548 :         else if (isspace((unsigned char) *(*endstr)))
    1706             :         {
    1707        1256 :             (*endstr)++;
    1708        1256 :             continue;
    1709             :         }
    1710             :         /* sign? then special or numeric timezone */
    1711         292 :         else if (*(*endstr) == '+' || *(*endstr) == '-')
    1712             :         {
    1713         204 :             *lp++ = *(*endstr)++;
    1714             :             /* soak up leading whitespace */
    1715         204 :             while (isspace((unsigned char) *(*endstr)))
    1716           0 :                 (*endstr)++;
    1717             :             /* numeric timezone? */
    1718         204 :             if (isdigit((unsigned char) *(*endstr)))
    1719             :             {
    1720         204 :                 ftype[nf] = DTK_TZ;
    1721         204 :                 *lp++ = *(*endstr)++;
    1722         408 :                 while (isdigit((unsigned char) *(*endstr)) ||
    1723         272 :                        (*(*endstr) == ':') || (*(*endstr) == '.'))
    1724         204 :                     *lp++ = *(*endstr)++;
    1725             :             }
    1726             :             /* special? */
    1727           0 :             else if (isalpha((unsigned char) *(*endstr)))
    1728             :             {
    1729           0 :                 ftype[nf] = DTK_SPECIAL;
    1730           0 :                 *lp++ = pg_tolower((unsigned char) *(*endstr)++);
    1731           0 :                 while (isalpha((unsigned char) *(*endstr)))
    1732           0 :                     *lp++ = pg_tolower((unsigned char) *(*endstr)++);
    1733             :             }
    1734             :             /* otherwise something wrong... */
    1735             :             else
    1736           0 :                 return -1;
    1737             :         }
    1738             :         /* ignore punctuation but use as delimiter */
    1739          88 :         else if (ispunct((unsigned char) *(*endstr)))
    1740             :         {
    1741          88 :             (*endstr)++;
    1742          88 :             continue;
    1743             :         }
    1744             :         /* otherwise, something is not right... */
    1745             :         else
    1746           0 :             return -1;
    1747             : 
    1748             :         /* force in a delimiter after each field */
    1749        2360 :         *lp++ = '\0';
    1750        2360 :         nf++;
    1751             :     }
    1752             : 
    1753         828 :     *numfields = nf;
    1754             : 
    1755         828 :     return 0;
    1756             : }                               /* ParseDateTime() */
    1757             : 
    1758             : 
    1759             : /* DecodeDateTime()
    1760             :  * Interpret previously parsed fields for general date and time.
    1761             :  * Return 0 if full date, 1 if only time, and -1 if problems.
    1762             :  *      External format(s):
    1763             :  *              "<weekday> <month>-<day>-<year> <hour>:<minute>:<second>"
    1764             :  *              "Fri Feb-7-1997 15:23:27"
    1765             :  *              "Feb-7-1997 15:23:27"
    1766             :  *              "2-7-1997 15:23:27"
    1767             :  *              "1997-2-7 15:23:27"
    1768             :  *              "1997.038 15:23:27"       (day of year 1-366)
    1769             :  *      Also supports input in compact time:
    1770             :  *              "970207 152327"
    1771             :  *              "97038 152327"
    1772             :  *              "20011225T040506.789-07"
    1773             :  *
    1774             :  * Use the system-provided functions to get the current time zone
    1775             :  *  if not specified in the input string.
    1776             :  * If the date is outside the time_t system-supported time range,
    1777             :  *  then assume UTC time zone. - thomas 1997-05-27
    1778             :  */
    1779             : int
    1780         712 : DecodeDateTime(char **field, int *ftype, int nf,
    1781             :                int *dtype, struct tm *tm, fsec_t *fsec, bool EuroDates)
    1782             : {
    1783         712 :     int         fmask = 0,
    1784             :                 tmask,
    1785             :                 type;
    1786         712 :     int         ptype = 0;      /* "prefix type" for ISO y2001m02d04 format */
    1787             :     int         i;
    1788             :     int         val;
    1789         712 :     int         mer = HR24;
    1790         712 :     bool        haveTextMonth = false;
    1791         712 :     bool        is2digits = false;
    1792         712 :     bool        bc = false;
    1793         712 :     int         t = 0;
    1794         712 :     int        *tzp = &t;
    1795             : 
    1796             :     /***
    1797             :      * We'll insist on at least all of the date fields, but initialize the
    1798             :      * remaining fields in case they are not set later...
    1799             :      ***/
    1800         712 :     *dtype = DTK_DATE;
    1801         712 :     tm->tm_hour = 0;
    1802         712 :     tm->tm_min = 0;
    1803         712 :     tm->tm_sec = 0;
    1804         712 :     *fsec = 0;
    1805             :     /* don't know daylight savings time status apriori */
    1806         712 :     tm->tm_isdst = -1;
    1807         712 :     if (tzp != NULL)
    1808         712 :         *tzp = 0;
    1809             : 
    1810        2484 :     for (i = 0; i < nf; i++)
    1811             :     {
    1812        1792 :         switch (ftype[i])
    1813             :         {
    1814         504 :             case DTK_DATE:
    1815             :                 /***
    1816             :                  * Integral julian day with attached time zone?
    1817             :                  * All other forms with JD will be separated into
    1818             :                  * distinct fields, so we handle just this case here.
    1819             :                  ***/
    1820         504 :                 if (ptype == DTK_JULIAN)
    1821             :                 {
    1822             :                     char       *cp;
    1823             :                     int         jday;
    1824             : 
    1825           0 :                     if (tzp == NULL)
    1826           0 :                         return -1;
    1827             : 
    1828           0 :                     jday = strtoint(field[i], &cp, 10);
    1829           0 :                     if (*cp != '-')
    1830           0 :                         return -1;
    1831             : 
    1832           0 :                     j2date(jday, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
    1833             :                     /* Get the time zone from the end of the string */
    1834           0 :                     if (DecodeTimezone(cp, tzp) != 0)
    1835           0 :                         return -1;
    1836             : 
    1837           0 :                     tmask = DTK_DATE_M | DTK_TIME_M | DTK_M(TZ);
    1838           0 :                     ptype = 0;
    1839           0 :                     break;
    1840             :                 }
    1841             :                 /***
    1842             :                  * Already have a date? Then this might be a POSIX time
    1843             :                  * zone with an embedded dash (e.g. "PST-3" == "EST") or
    1844             :                  * a run-together time with trailing time zone (e.g. hhmmss-zz).
    1845             :                  * - thomas 2001-12-25
    1846             :                  ***/
    1847         504 :                 else if (((fmask & DTK_DATE_M) == DTK_DATE_M)
    1848         504 :                          || (ptype != 0))
    1849             :                 {
    1850             :                     /* No time zone accepted? Then quit... */
    1851           0 :                     if (tzp == NULL)
    1852           0 :                         return -1;
    1853             : 
    1854           0 :                     if (isdigit((unsigned char) *field[i]) || ptype != 0)
    1855           0 :                     {
    1856             :                         char       *cp;
    1857             : 
    1858           0 :                         if (ptype != 0)
    1859             :                         {
    1860             :                             /* Sanity check; should not fail this test */
    1861           0 :                             if (ptype != DTK_TIME)
    1862           0 :                                 return -1;
    1863           0 :                             ptype = 0;
    1864             :                         }
    1865             : 
    1866             :                         /*
    1867             :                          * Starts with a digit but we already have a time
    1868             :                          * field? Then we are in trouble with a date and time
    1869             :                          * already...
    1870             :                          */
    1871           0 :                         if ((fmask & DTK_TIME_M) == DTK_TIME_M)
    1872           0 :                             return -1;
    1873             : 
    1874           0 :                         if ((cp = strchr(field[i], '-')) == NULL)
    1875           0 :                             return -1;
    1876             : 
    1877             :                         /* Get the time zone from the end of the string */
    1878           0 :                         if (DecodeTimezone(cp, tzp) != 0)
    1879           0 :                             return -1;
    1880           0 :                         *cp = '\0';
    1881             : 
    1882             :                         /*
    1883             :                          * Then read the rest of the field as a concatenated
    1884             :                          * time
    1885             :                          */
    1886           0 :                         if ((ftype[i] = DecodeNumberField(strlen(field[i]), field[i], fmask,
    1887             :                                                           &tmask, tm, fsec, &is2digits)) < 0)
    1888           0 :                             return -1;
    1889             : 
    1890             :                         /*
    1891             :                          * modify tmask after returning from
    1892             :                          * DecodeNumberField()
    1893             :                          */
    1894           0 :                         tmask |= DTK_M(TZ);
    1895             :                     }
    1896             :                     else
    1897             :                     {
    1898           0 :                         if (DecodePosixTimezone(field[i], tzp) != 0)
    1899           0 :                             return -1;
    1900             : 
    1901           0 :                         ftype[i] = DTK_TZ;
    1902           0 :                         tmask = DTK_M(TZ);
    1903             :                     }
    1904             :                 }
    1905         504 :                 else if (DecodeDate(field[i], fmask, &tmask, tm, EuroDates) != 0)
    1906           0 :                     return -1;
    1907         504 :                 break;
    1908             : 
    1909         496 :             case DTK_TIME:
    1910         496 :                 if (DecodeTime(field[i], &tmask, tm, fsec) != 0)
    1911           0 :                     return -1;
    1912             : 
    1913             :                 /*
    1914             :                  * Check upper limit on hours; other limits checked in
    1915             :                  * DecodeTime()
    1916             :                  */
    1917             :                 /* test for > 24:00:00 */
    1918         496 :                 if (tm->tm_hour > 24 ||
    1919         492 :                     (tm->tm_hour == 24 && (tm->tm_min > 0 || tm->tm_sec > 0)))
    1920           4 :                     return -1;
    1921         492 :                 break;
    1922             : 
    1923         204 :             case DTK_TZ:
    1924             :                 {
    1925             :                     int         tz;
    1926             : 
    1927         204 :                     if (tzp == NULL)
    1928           0 :                         return -1;
    1929             : 
    1930         204 :                     if (DecodeTimezone(field[i], &tz) != 0)
    1931           0 :                         return -1;
    1932             : 
    1933             :                     /*
    1934             :                      * Already have a time zone? Then maybe this is the second
    1935             :                      * field of a POSIX time: EST+3 (equivalent to PST)
    1936             :                      */
    1937         204 :                     if (i > 0 && (fmask & DTK_M(TZ)) != 0 &&
    1938           0 :                         ftype[i - 1] == DTK_TZ &&
    1939           0 :                         isalpha((unsigned char) *field[i - 1]))
    1940             :                     {
    1941           0 :                         *tzp -= tz;
    1942           0 :                         tmask = 0;
    1943             :                     }
    1944             :                     else
    1945             :                     {
    1946         204 :                         *tzp = tz;
    1947         204 :                         tmask = DTK_M(TZ);
    1948             :                     }
    1949             :                 }
    1950         204 :                 break;
    1951             : 
    1952         308 :             case DTK_NUMBER:
    1953             : 
    1954             :                 /*
    1955             :                  * Was this an "ISO date" with embedded field labels? An
    1956             :                  * example is "y2001m02d04" - thomas 2001-02-04
    1957             :                  */
    1958         308 :                 if (ptype != 0)
    1959             :                 {
    1960             :                     char       *cp;
    1961             :                     int         value;
    1962             : 
    1963          24 :                     value = strtoint(field[i], &cp, 10);
    1964             : 
    1965             :                     /*
    1966             :                      * only a few kinds are allowed to have an embedded
    1967             :                      * decimal
    1968             :                      */
    1969          24 :                     if (*cp == '.')
    1970             :                         switch (ptype)
    1971             :                         {
    1972           0 :                             case DTK_JULIAN:
    1973             :                             case DTK_TIME:
    1974             :                             case DTK_SECOND:
    1975           0 :                                 break;
    1976           0 :                             default:
    1977           0 :                                 return 1;
    1978             :                                 break;
    1979             :                         }
    1980          24 :                     else if (*cp != '\0')
    1981           0 :                         return -1;
    1982             : 
    1983             :                     switch (ptype)
    1984             :                     {
    1985           0 :                         case DTK_YEAR:
    1986           0 :                             tm->tm_year = value;
    1987           0 :                             tmask = DTK_M(YEAR);
    1988           0 :                             break;
    1989             : 
    1990           0 :                         case DTK_MONTH:
    1991             : 
    1992             :                             /*
    1993             :                              * already have a month and hour? then assume
    1994             :                              * minutes
    1995             :                              */
    1996           0 :                             if ((fmask & DTK_M(MONTH)) != 0 &&
    1997           0 :                                 (fmask & DTK_M(HOUR)) != 0)
    1998             :                             {
    1999           0 :                                 tm->tm_min = value;
    2000           0 :                                 tmask = DTK_M(MINUTE);
    2001             :                             }
    2002             :                             else
    2003             :                             {
    2004           0 :                                 tm->tm_mon = value;
    2005           0 :                                 tmask = DTK_M(MONTH);
    2006             :                             }
    2007           0 :                             break;
    2008             : 
    2009           0 :                         case DTK_DAY:
    2010           0 :                             tm->tm_mday = value;
    2011           0 :                             tmask = DTK_M(DAY);
    2012           0 :                             break;
    2013             : 
    2014           0 :                         case DTK_HOUR:
    2015           0 :                             tm->tm_hour = value;
    2016           0 :                             tmask = DTK_M(HOUR);
    2017           0 :                             break;
    2018             : 
    2019           0 :                         case DTK_MINUTE:
    2020           0 :                             tm->tm_min = value;
    2021           0 :                             tmask = DTK_M(MINUTE);
    2022           0 :                             break;
    2023             : 
    2024           0 :                         case DTK_SECOND:
    2025           0 :                             tm->tm_sec = value;
    2026           0 :                             tmask = DTK_M(SECOND);
    2027           0 :                             if (*cp == '.')
    2028             :                             {
    2029             :                                 double      frac;
    2030             : 
    2031           0 :                                 frac = strtod(cp, &cp);
    2032           0 :                                 if (*cp != '\0')
    2033           0 :                                     return -1;
    2034           0 :                                 *fsec = frac * 1000000;
    2035             :                             }
    2036           0 :                             break;
    2037             : 
    2038           0 :                         case DTK_TZ:
    2039           0 :                             tmask = DTK_M(TZ);
    2040           0 :                             if (DecodeTimezone(field[i], tzp) != 0)
    2041           0 :                                 return -1;
    2042           0 :                             break;
    2043             : 
    2044          24 :                         case DTK_JULIAN:
    2045             :                             /***
    2046             :                              * previous field was a label for "julian date"?
    2047             :                              ***/
    2048          24 :                             tmask = DTK_DATE_M;
    2049          24 :                             j2date(value, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
    2050             :                             /* fractional Julian Day? */
    2051          24 :                             if (*cp == '.')
    2052             :                             {
    2053             :                                 double      time;
    2054             : 
    2055           0 :                                 time = strtod(cp, &cp);
    2056           0 :                                 if (*cp != '\0')
    2057           0 :                                     return -1;
    2058             : 
    2059           0 :                                 tmask |= DTK_TIME_M;
    2060           0 :                                 dt2time((time * USECS_PER_DAY), &tm->tm_hour, &tm->tm_min, &tm->tm_sec, fsec);
    2061             :                             }
    2062          24 :                             break;
    2063             : 
    2064           0 :                         case DTK_TIME:
    2065             :                             /* previous field was "t" for ISO time */
    2066           0 :                             if ((ftype[i] = DecodeNumberField(strlen(field[i]), field[i], (fmask | DTK_DATE_M),
    2067             :                                                               &tmask, tm, fsec, &is2digits)) < 0)
    2068           0 :                                 return -1;
    2069             : 
    2070           0 :                             if (tmask != DTK_TIME_M)
    2071           0 :                                 return -1;
    2072           0 :                             break;
    2073             : 
    2074           0 :                         default:
    2075           0 :                             return -1;
    2076             :                             break;
    2077             :                     }
    2078             : 
    2079          24 :                     ptype = 0;
    2080          24 :                     *dtype = DTK_DATE;
    2081             :                 }
    2082             :                 else
    2083             :                 {
    2084             :                     char       *cp;
    2085             :                     int         flen;
    2086             : 
    2087         284 :                     flen = strlen(field[i]);
    2088         284 :                     cp = strchr(field[i], '.');
    2089             : 
    2090             :                     /* Embedded decimal and no date yet? */
    2091         284 :                     if (cp != NULL && !(fmask & DTK_DATE_M))
    2092             :                     {
    2093          28 :                         if (DecodeDate(field[i], fmask, &tmask, tm, EuroDates) != 0)
    2094           4 :                             return -1;
    2095             :                     }
    2096             :                     /* embedded decimal and several digits before? */
    2097         256 :                     else if (cp != NULL && flen - strlen(cp) > 2)
    2098             :                     {
    2099             :                         /*
    2100             :                          * Interpret as a concatenated date or time Set the
    2101             :                          * type field to allow decoding other fields later.
    2102             :                          * Example: 20011223 or 040506
    2103             :                          */
    2104           0 :                         if ((ftype[i] = DecodeNumberField(flen, field[i], fmask,
    2105             :                                                           &tmask, tm, fsec, &is2digits)) < 0)
    2106           0 :                             return -1;
    2107             :                     }
    2108         256 :                     else if (flen > 4)
    2109             :                     {
    2110          56 :                         if ((ftype[i] = DecodeNumberField(flen, field[i], fmask,
    2111             :                                                           &tmask, tm, fsec, &is2digits)) < 0)
    2112           0 :                             return -1;
    2113             :                     }
    2114             :                     /* otherwise it is a single date/time field... */
    2115         200 :                     else if (DecodeNumber(flen, field[i], fmask,
    2116             :                                           &tmask, tm, fsec, &is2digits, EuroDates) != 0)
    2117           0 :                         return -1;
    2118             :                 }
    2119         304 :                 break;
    2120             : 
    2121         280 :             case DTK_STRING:
    2122             :             case DTK_SPECIAL:
    2123         280 :                 type = DecodeSpecial(i, field[i], &val);
    2124         280 :                 if (type == IGNORE_DTF)
    2125           0 :                     continue;
    2126             : 
    2127         280 :                 tmask = DTK_M(type);
    2128             :                 switch (type)
    2129             :                 {
    2130           0 :                     case RESERV:
    2131           0 :                         switch (val)
    2132             :                         {
    2133           0 :                             case DTK_NOW:
    2134           0 :                                 tmask = (DTK_DATE_M | DTK_TIME_M | DTK_M(TZ));
    2135           0 :                                 *dtype = DTK_DATE;
    2136           0 :                                 GetCurrentDateTime(tm);
    2137           0 :                                 break;
    2138             : 
    2139           0 :                             case DTK_YESTERDAY:
    2140           0 :                                 tmask = DTK_DATE_M;
    2141           0 :                                 *dtype = DTK_DATE;
    2142           0 :                                 GetCurrentDateTime(tm);
    2143           0 :                                 j2date(date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - 1,
    2144             :                                        &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
    2145           0 :                                 tm->tm_hour = 0;
    2146           0 :                                 tm->tm_min = 0;
    2147           0 :                                 tm->tm_sec = 0;
    2148           0 :                                 break;
    2149             : 
    2150           0 :                             case DTK_TODAY:
    2151           0 :                                 tmask = DTK_DATE_M;
    2152           0 :                                 *dtype = DTK_DATE;
    2153           0 :                                 GetCurrentDateTime(tm);
    2154           0 :                                 tm->tm_hour = 0;
    2155           0 :                                 tm->tm_min = 0;
    2156           0 :                                 tm->tm_sec = 0;
    2157           0 :                                 break;
    2158             : 
    2159           0 :                             case DTK_TOMORROW:
    2160           0 :                                 tmask = DTK_DATE_M;
    2161           0 :                                 *dtype = DTK_DATE;
    2162           0 :                                 GetCurrentDateTime(tm);
    2163           0 :                                 j2date(date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) + 1,
    2164             :                                        &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
    2165           0 :                                 tm->tm_hour = 0;
    2166           0 :                                 tm->tm_min = 0;
    2167           0 :                                 tm->tm_sec = 0;
    2168           0 :                                 break;
    2169             : 
    2170           0 :                             case DTK_ZULU:
    2171           0 :                                 tmask = (DTK_TIME_M | DTK_M(TZ));
    2172           0 :                                 *dtype = DTK_DATE;
    2173           0 :                                 tm->tm_hour = 0;
    2174           0 :                                 tm->tm_min = 0;
    2175           0 :                                 tm->tm_sec = 0;
    2176           0 :                                 if (tzp != NULL)
    2177           0 :                                     *tzp = 0;
    2178           0 :                                 break;
    2179             : 
    2180           0 :                             default:
    2181           0 :                                 *dtype = val;
    2182             :                         }
    2183             : 
    2184           0 :                         break;
    2185             : 
    2186         100 :                     case MONTH:
    2187             : 
    2188             :                         /*
    2189             :                          * already have a (numeric) month? then see if we can
    2190             :                          * substitute...
    2191             :                          */
    2192         100 :                         if ((fmask & DTK_M(MONTH)) && !haveTextMonth &&
    2193           8 :                             !(fmask & DTK_M(DAY)) && tm->tm_mon >= 1 && tm->tm_mon <= 31)
    2194             :                         {
    2195           8 :                             tm->tm_mday = tm->tm_mon;
    2196           8 :                             tmask = DTK_M(DAY);
    2197             :                         }
    2198         100 :                         haveTextMonth = true;
    2199         100 :                         tm->tm_mon = val;
    2200         100 :                         break;
    2201             : 
    2202           0 :                     case DTZMOD:
    2203             : 
    2204             :                         /*
    2205             :                          * daylight savings time modifier (solves "MET DST"
    2206             :                          * syntax)
    2207             :                          */
    2208           0 :                         tmask |= DTK_M(DTZ);
    2209           0 :                         tm->tm_isdst = 1;
    2210           0 :                         if (tzp == NULL)
    2211           0 :                             return -1;
    2212           0 :                         *tzp -= val;
    2213           0 :                         break;
    2214             : 
    2215          68 :                     case DTZ:
    2216             : 
    2217             :                         /*
    2218             :                          * set mask for TZ here _or_ check for DTZ later when
    2219             :                          * getting default timezone
    2220             :                          */
    2221          68 :                         tmask |= DTK_M(TZ);
    2222          68 :                         tm->tm_isdst = 1;
    2223          68 :                         if (tzp == NULL)
    2224           0 :                             return -1;
    2225          68 :                         *tzp = -val;
    2226          68 :                         ftype[i] = DTK_TZ;
    2227          68 :                         break;
    2228             : 
    2229           0 :                     case TZ:
    2230           0 :                         tm->tm_isdst = 0;
    2231           0 :                         if (tzp == NULL)
    2232           0 :                             return -1;
    2233           0 :                         *tzp = -val;
    2234           0 :                         ftype[i] = DTK_TZ;
    2235           0 :                         break;
    2236             : 
    2237           0 :                     case IGNORE_DTF:
    2238           0 :                         break;
    2239             : 
    2240           0 :                     case AMPM:
    2241           0 :                         mer = val;
    2242           0 :                         break;
    2243             : 
    2244          24 :                     case ADBC:
    2245          24 :                         bc = (val == BC);
    2246          24 :                         break;
    2247             : 
    2248          52 :                     case DOW:
    2249          52 :                         tm->tm_wday = val;
    2250          52 :                         break;
    2251             : 
    2252          24 :                     case UNITS:
    2253          24 :                         tmask = 0;
    2254          24 :                         ptype = val;
    2255          24 :                         break;
    2256             : 
    2257           0 :                     case ISOTIME:
    2258             : 
    2259             :                         /*
    2260             :                          * This is a filler field "t" indicating that the next
    2261             :                          * field is time. Try to verify that this is sensible.
    2262             :                          */
    2263           0 :                         tmask = 0;
    2264             : 
    2265             :                         /* No preceding date? Then quit... */
    2266           0 :                         if ((fmask & DTK_DATE_M) != DTK_DATE_M)
    2267           0 :                             return -1;
    2268             : 
    2269             :                         /***
    2270             :                          * We will need one of the following fields:
    2271             :                          *  DTK_NUMBER should be hhmmss.fff
    2272             :                          *  DTK_TIME should be hh:mm:ss.fff
    2273             :                          *  DTK_DATE should be hhmmss-zz
    2274             :                          ***/
    2275           0 :                         if (i >= nf - 1 ||
    2276           0 :                             (ftype[i + 1] != DTK_NUMBER &&
    2277           0 :                              ftype[i + 1] != DTK_TIME &&
    2278           0 :                              ftype[i + 1] != DTK_DATE))
    2279           0 :                             return -1;
    2280             : 
    2281           0 :                         ptype = val;
    2282           0 :                         break;
    2283             : 
    2284          12 :                     default:
    2285          12 :                         return -1;
    2286             :                 }
    2287         268 :                 break;
    2288             : 
    2289           0 :             default:
    2290           0 :                 return -1;
    2291             :         }
    2292             : 
    2293        1772 :         if (tmask & fmask)
    2294           0 :             return -1;
    2295        1772 :         fmask |= tmask;
    2296             :     }
    2297             : 
    2298             :     /* there is no year zero in AD/BC notation; i.e. "1 BC" == year 0 */
    2299         692 :     if (bc)
    2300             :     {
    2301          24 :         if (tm->tm_year > 0)
    2302          24 :             tm->tm_year = -(tm->tm_year - 1);
    2303             :         else
    2304           0 :             return -1;
    2305             :     }
    2306         668 :     else if (is2digits)
    2307             :     {
    2308          24 :         if (tm->tm_year < 70)
    2309           0 :             tm->tm_year += 2000;
    2310          24 :         else if (tm->tm_year < 100)
    2311          24 :             tm->tm_year += 1900;
    2312             :     }
    2313             : 
    2314         692 :     if (mer != HR24 && tm->tm_hour > 12)
    2315           0 :         return -1;
    2316         692 :     if (mer == AM && tm->tm_hour == 12)
    2317           0 :         tm->tm_hour = 0;
    2318         692 :     else if (mer == PM && tm->tm_hour != 12)
    2319           0 :         tm->tm_hour += 12;
    2320             : 
    2321             :     /* do additional checking for full date specs... */
    2322         692 :     if (*dtype == DTK_DATE)
    2323             :     {
    2324         692 :         if ((fmask & DTK_DATE_M) != DTK_DATE_M)
    2325           0 :             return ((fmask & DTK_TIME_M) == DTK_TIME_M) ? 1 : -1;
    2326             : 
    2327             :         /*
    2328             :          * check for valid day of month, now that we know for sure the month
    2329             :          * and year...
    2330             :          */
    2331         692 :         if (tm->tm_mday < 1 || tm->tm_mday > day_tab[isleap(tm->tm_year)][tm->tm_mon - 1])
    2332           0 :             return -1;
    2333             : 
    2334             :         /*
    2335             :          * backend tried to find local timezone here but we don't use the
    2336             :          * result afterwards anyway so we only check for this error: daylight
    2337             :          * savings time modifier but no standard timezone?
    2338             :          */
    2339         692 :         if ((fmask & DTK_DATE_M) == DTK_DATE_M && tzp != NULL && !(fmask & DTK_M(TZ)) && (fmask & DTK_M(DTZMOD)))
    2340           0 :             return -1;
    2341             :     }
    2342             : 
    2343         692 :     return 0;
    2344             : }                               /* DecodeDateTime() */
    2345             : 
    2346             : /* Function works as follows:
    2347             :  *
    2348             :  *
    2349             :  * */
    2350             : 
    2351             : static char *
    2352         456 : find_end_token(char *str, char *fmt)
    2353             : {
    2354             :     /*
    2355             :      * str: here is28the day12the hour fmt: here is%dthe day%hthe hour
    2356             :      *
    2357             :      * we extract the 28, we read the percent sign and the type "d" then this
    2358             :      * functions gets called as find_end_token("28the day12the hour", "the
    2359             :      * day%hthehour")
    2360             :      *
    2361             :      * fmt points to "the day%hthehour", next_percent points to %hthehour and
    2362             :      * we have to find a match for everything between these positions ("the
    2363             :      * day"). We look for "the day" in str and know that the pattern we are
    2364             :      * about to scan ends where this string starts (right after the "28")
    2365             :      *
    2366             :      * At the end, *fmt is '\0' and *str isn't. end_position then is
    2367             :      * unchanged.
    2368             :      */
    2369         456 :     char       *end_position = NULL;
    2370             :     char       *next_percent,
    2371         456 :                *subst_location = NULL;
    2372         456 :     int         scan_offset = 0;
    2373             :     char        last_char;
    2374             : 
    2375             :     /* are we at the end? */
    2376         456 :     if (!*fmt)
    2377             :     {
    2378          68 :         end_position = fmt;
    2379          68 :         return end_position;
    2380             :     }
    2381             : 
    2382             :     /* not at the end */
    2383         396 :     while (fmt[scan_offset] == '%' && fmt[scan_offset + 1])
    2384             :     {
    2385             :         /*
    2386             :          * there is no delimiter, skip to the next delimiter if we're reading
    2387             :          * a number and then something that is not a number "9:15pm", we might
    2388             :          * be able to recover with the strtol end pointer. Go for the next
    2389             :          * percent sign
    2390             :          */
    2391           8 :         scan_offset += 2;
    2392             :     }
    2393         388 :     next_percent = strchr(fmt + scan_offset, '%');
    2394         388 :     if (next_percent)
    2395             :     {
    2396             :         /*
    2397             :          * we don't want to allocate extra memory, so we temporarily set the
    2398             :          * '%' sign to '\0' and call strstr However since we allow whitespace
    2399             :          * to float around everything, we have to shorten the pattern until we
    2400             :          * reach a non-whitespace character
    2401             :          */
    2402             : 
    2403         376 :         subst_location = next_percent;
    2404         428 :         while (*(subst_location - 1) == ' ' && subst_location - 1 > fmt + scan_offset)
    2405          52 :             subst_location--;
    2406         376 :         last_char = *subst_location;
    2407         376 :         *subst_location = '\0';
    2408             : 
    2409             :         /*
    2410             :          * the haystack is the str and the needle is the original fmt but it
    2411             :          * ends at the position where the next percent sign would be
    2412             :          */
    2413             : 
    2414             :         /*
    2415             :          * There is one special case. Imagine: str = " 2", fmt = "%d %...",
    2416             :          * since we want to allow blanks as "dynamic" padding we have to
    2417             :          * accept this. Now, we are called with a fmt of " %..." and look for
    2418             :          * " " in str. We find it at the first position and never read the
    2419             :          * 2...
    2420             :          */
    2421         376 :         while (*str == ' ')
    2422           0 :             str++;
    2423         376 :         end_position = strstr(str, fmt + scan_offset);
    2424         376 :         *subst_location = last_char;
    2425             :     }
    2426             :     else
    2427             :     {
    2428             :         /*
    2429             :          * there is no other percent sign. So everything up to the end has to
    2430             :          * match.
    2431             :          */
    2432          12 :         end_position = str + strlen(str);
    2433             :     }
    2434         388 :     if (!end_position)
    2435             :     {
    2436             :         /*
    2437             :          * maybe we have the following case:
    2438             :          *
    2439             :          * str = "4:15am" fmt = "%M:%S %p"
    2440             :          *
    2441             :          * at this place we could have
    2442             :          *
    2443             :          * str = "15am" fmt = " %p"
    2444             :          *
    2445             :          * and have set fmt to " " because overwrote the % sign with a NULL
    2446             :          *
    2447             :          * In this case where we would have to match a space but can't find
    2448             :          * it, set end_position to the end of the string
    2449             :          */
    2450           4 :         if ((fmt + scan_offset)[0] == ' ' && fmt + scan_offset + 1 == subst_location)
    2451           4 :             end_position = str + strlen(str);
    2452             :     }
    2453         388 :     return end_position;
    2454             : }
    2455             : 
    2456             : static int
    2457         456 : pgtypes_defmt_scan(union un_fmt_comb *scan_val, int scan_type, char **pstr, char *pfmt)
    2458             : {
    2459             :     /*
    2460             :      * scan everything between pstr and pstr_end. This is not including the
    2461             :      * last character so we might set it to '\0' for the parsing
    2462             :      */
    2463             : 
    2464             :     char        last_char;
    2465         456 :     int         err = 0;
    2466             :     char       *pstr_end;
    2467         456 :     char       *strtol_end = NULL;
    2468             : 
    2469         456 :     while (**pstr == ' ')
    2470           0 :         pstr++;
    2471         456 :     pstr_end = find_end_token(*pstr, pfmt);
    2472         456 :     if (!pstr_end)
    2473             :     {
    2474             :         /* there was an error, no match */
    2475           0 :         return 1;
    2476             :     }
    2477         456 :     last_char = *pstr_end;
    2478         456 :     *pstr_end = '\0';
    2479             : 
    2480         456 :     switch (scan_type)
    2481             :     {
    2482         404 :         case PGTYPES_TYPE_UINT:
    2483             : 
    2484             :             /*
    2485             :              * numbers may be blank-padded, this is the only deviation from
    2486             :              * the fmt-string we accept
    2487             :              */
    2488         404 :             while (**pstr == ' ')
    2489           0 :                 (*pstr)++;
    2490         404 :             errno = 0;
    2491         404 :             scan_val->uint_val = (unsigned int) strtol(*pstr, &strtol_end, 10);
    2492         404 :             if (errno)
    2493           0 :                 err = 1;
    2494         404 :             break;
    2495           4 :         case PGTYPES_TYPE_UINT_LONG:
    2496           4 :             while (**pstr == ' ')
    2497           0 :                 (*pstr)++;
    2498           4 :             errno = 0;
    2499           4 :             scan_val->luint_val = (unsigned long int) strtol(*pstr, &strtol_end, 10);
    2500           4 :             if (errno)
    2501           0 :                 err = 1;
    2502           4 :             break;
    2503          48 :         case PGTYPES_TYPE_STRING_MALLOCED:
    2504          48 :             scan_val->str_val = pgtypes_strdup(*pstr);
    2505          48 :             if (scan_val->str_val == NULL)
    2506           0 :                 err = 1;
    2507          48 :             break;
    2508             :     }
    2509         456 :     if (strtol_end && *strtol_end)
    2510          36 :         *pstr = strtol_end;
    2511             :     else
    2512         420 :         *pstr = pstr_end;
    2513         456 :     *pstr_end = last_char;
    2514         456 :     return err;
    2515             : }
    2516             : 
    2517             : /* XXX range checking */
    2518             : int
    2519          96 : PGTYPEStimestamp_defmt_scan(char **str, char *fmt, timestamp * d,
    2520             :                             int *year, int *month, int *day,
    2521             :                             int *hour, int *minute, int *second,
    2522             :                             int *tz)
    2523             : {
    2524             :     union un_fmt_comb scan_val;
    2525             :     int         scan_type;
    2526             : 
    2527             :     char       *pstr,
    2528             :                *pfmt,
    2529             :                *tmp;
    2530          96 :     int         err = 1;
    2531             :     unsigned int j;
    2532             :     struct tm   tm;
    2533             : 
    2534          96 :     pfmt = fmt;
    2535          96 :     pstr = *str;
    2536             : 
    2537        1096 :     while (*pfmt)
    2538             :     {
    2539        1008 :         err = 0;
    2540        1416 :         while (*pfmt == ' ')
    2541         408 :             pfmt++;
    2542        1500 :         while (*pstr == ' ')
    2543         492 :             pstr++;
    2544        1008 :         if (*pfmt != '%')
    2545             :         {
    2546         392 :             if (*pfmt == *pstr)
    2547             :             {
    2548         384 :                 pfmt++;
    2549         384 :                 pstr++;
    2550             :             }
    2551             :             else
    2552             :             {
    2553             :                 /* Error: no match */
    2554           8 :                 err = 1;
    2555           8 :                 return err;
    2556             :             }
    2557         384 :             continue;
    2558             :         }
    2559             :         /* here *pfmt equals '%' */
    2560         616 :         pfmt++;
    2561         616 :         switch (*pfmt)
    2562             :         {
    2563          36 :             case 'a':
    2564          36 :                 pfmt++;
    2565             : 
    2566             :                 /*
    2567             :                  * we parse the day and see if it is a week day but we do not
    2568             :                  * check if the week day really matches the date
    2569             :                  */
    2570          36 :                 err = 1;
    2571          36 :                 j = 0;
    2572         100 :                 while (pgtypes_date_weekdays_short[j])
    2573             :                 {
    2574         100 :                     if (strncmp(pgtypes_date_weekdays_short[j], pstr,
    2575         100 :                                 strlen(pgtypes_date_weekdays_short[j])) == 0)
    2576             :                     {
    2577             :                         /* found it */
    2578          36 :                         err = 0;
    2579          36 :                         pstr += strlen(pgtypes_date_weekdays_short[j]);
    2580          36 :                         break;
    2581             :                     }
    2582          64 :                     j++;
    2583             :                 }
    2584          36 :                 break;
    2585           0 :             case 'A':
    2586             :                 /* see note above */
    2587           0 :                 pfmt++;
    2588           0 :                 err = 1;
    2589           0 :                 j = 0;
    2590           0 :                 while (days[j])
    2591             :                 {
    2592           0 :                     if (strncmp(days[j], pstr, strlen(days[j])) == 0)
    2593             :                     {
    2594             :                         /* found it */
    2595           0 :                         err = 0;
    2596           0 :                         pstr += strlen(days[j]);
    2597           0 :                         break;
    2598             :                     }
    2599           0 :                     j++;
    2600             :                 }
    2601           0 :                 break;
    2602          48 :             case 'b':
    2603             :             case 'h':
    2604          48 :                 pfmt++;
    2605          48 :                 err = 1;
    2606          48 :                 j = 0;
    2607         296 :                 while (months[j])
    2608             :                 {
    2609         296 :                     if (strncmp(months[j], pstr, strlen(months[j])) == 0)
    2610             :                     {
    2611             :                         /* found it */
    2612          48 :                         err = 0;
    2613          48 :                         pstr += strlen(months[j]);
    2614          48 :                         *month = j + 1;
    2615          48 :                         break;
    2616             :                     }
    2617         248 :                     j++;
    2618             :                 }
    2619          48 :                 break;
    2620          28 :             case 'B':
    2621             :                 /* see note above */
    2622          28 :                 pfmt++;
    2623          28 :                 err = 1;
    2624          28 :                 j = 0;
    2625         228 :                 while (pgtypes_date_months[j])
    2626             :                 {
    2627         228 :                     if (strncmp(pgtypes_date_months[j], pstr, strlen(pgtypes_date_months[j])) == 0)
    2628             :                     {
    2629             :                         /* found it */
    2630          28 :                         err = 0;
    2631          28 :                         pstr += strlen(pgtypes_date_months[j]);
    2632          28 :                         *month = j + 1;
    2633          28 :                         break;
    2634             :                     }
    2635         200 :                     j++;
    2636             :                 }
    2637          28 :                 break;
    2638           0 :             case 'c':
    2639             :                 /* XXX */
    2640           0 :                 break;
    2641           8 :             case 'C':
    2642           8 :                 pfmt++;
    2643           8 :                 scan_type = PGTYPES_TYPE_UINT;
    2644           8 :                 err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt);
    2645           8 :                 *year = scan_val.uint_val * 100;
    2646           8 :                 break;
    2647          84 :             case 'd':
    2648             :             case 'e':
    2649          84 :                 pfmt++;
    2650          84 :                 scan_type = PGTYPES_TYPE_UINT;
    2651          84 :                 err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt);
    2652          84 :                 *day = scan_val.uint_val;
    2653          84 :                 break;
    2654           0 :             case 'D':
    2655             : 
    2656             :                 /*
    2657             :                  * we have to concatenate the strings in order to be able to
    2658             :                  * find the end of the substitution
    2659             :                  */
    2660           0 :                 pfmt++;
    2661           0 :                 tmp = pgtypes_alloc(strlen("%m/%d/%y") + strlen(pstr) + 1);
    2662           0 :                 if (!tmp)
    2663           0 :                     return 1;
    2664           0 :                 strcpy(tmp, "%m/%d/%y");
    2665           0 :                 strcat(tmp, pfmt);
    2666           0 :                 err = PGTYPEStimestamp_defmt_scan(&pstr, tmp, d, year, month, day, hour, minute, second, tz);
    2667           0 :                 free(tmp);
    2668           0 :                 return err;
    2669           8 :             case 'm':
    2670           8 :                 pfmt++;
    2671           8 :                 scan_type = PGTYPES_TYPE_UINT;
    2672           8 :                 err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt);
    2673           8 :                 *month = scan_val.uint_val;
    2674           8 :                 break;
    2675           8 :             case 'y':
    2676             :             case 'g':           /* XXX difference to y (ISO) */
    2677           8 :                 pfmt++;
    2678           8 :                 scan_type = PGTYPES_TYPE_UINT;
    2679           8 :                 err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt);
    2680           8 :                 if (*year < 0)
    2681             :                 {
    2682             :                     /* not yet set */
    2683           4 :                     *year = scan_val.uint_val;
    2684             :                 }
    2685             :                 else
    2686           4 :                     *year += scan_val.uint_val;
    2687           8 :                 if (*year < 100)
    2688           4 :                     *year += 1900;
    2689           8 :                 break;
    2690           0 :             case 'G':
    2691             :                 /* XXX difference to %V (ISO) */
    2692           0 :                 pfmt++;
    2693           0 :                 scan_type = PGTYPES_TYPE_UINT;
    2694           0 :                 err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt);
    2695           0 :                 *year = scan_val.uint_val;
    2696           0 :                 break;
    2697          84 :             case 'H':
    2698             :             case 'I':
    2699             :             case 'k':
    2700             :             case 'l':
    2701          84 :                 pfmt++;
    2702          84 :                 scan_type = PGTYPES_TYPE_UINT;
    2703          84 :                 err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt);
    2704          84 :                 *hour += scan_val.uint_val;
    2705          84 :                 break;
    2706           0 :             case 'j':
    2707           0 :                 pfmt++;
    2708           0 :                 scan_type = PGTYPES_TYPE_UINT;
    2709           0 :                 err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt);
    2710             : 
    2711             :                 /*
    2712             :                  * XXX what should we do with that? We could say that it's
    2713             :                  * sufficient if we have the year and the day within the year
    2714             :                  * to get at least a specific day.
    2715             :                  */
    2716           0 :                 break;
    2717          80 :             case 'M':
    2718          80 :                 pfmt++;
    2719          80 :                 scan_type = PGTYPES_TYPE_UINT;
    2720          80 :                 err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt);
    2721          80 :                 *minute = scan_val.uint_val;
    2722          80 :                 break;
    2723           8 :             case 'n':
    2724           8 :                 pfmt++;
    2725           8 :                 if (*pstr == '\n')
    2726           8 :                     pstr++;
    2727             :                 else
    2728           0 :                     err = 1;
    2729           8 :                 break;
    2730          16 :             case 'p':
    2731          16 :                 err = 1;
    2732          16 :                 pfmt++;
    2733          16 :                 if (strncmp(pstr, "am", 2) == 0)
    2734             :                 {
    2735          12 :                     *hour += 0;
    2736          12 :                     err = 0;
    2737          12 :                     pstr += 2;
    2738             :                 }
    2739          16 :                 if (strncmp(pstr, "a.m.", 4) == 0)
    2740             :                 {
    2741           0 :                     *hour += 0;
    2742           0 :                     err = 0;
    2743           0 :                     pstr += 4;
    2744             :                 }
    2745          16 :                 if (strncmp(pstr, "pm", 2) == 0)
    2746             :                 {
    2747           4 :                     *hour += 12;
    2748           4 :                     err = 0;
    2749           4 :                     pstr += 2;
    2750             :                 }
    2751          16 :                 if (strncmp(pstr, "p.m.", 4) == 0)
    2752             :                 {
    2753           0 :                     *hour += 12;
    2754           0 :                     err = 0;
    2755           0 :                     pstr += 4;
    2756             :                 }
    2757          16 :                 break;
    2758           4 :             case 'P':
    2759           4 :                 err = 1;
    2760           4 :                 pfmt++;
    2761           4 :                 if (strncmp(pstr, "AM", 2) == 0)
    2762             :                 {
    2763           0 :                     *hour += 0;
    2764           0 :                     err = 0;
    2765           0 :                     pstr += 2;
    2766             :                 }
    2767           4 :                 if (strncmp(pstr, "A.M.", 4) == 0)
    2768             :                 {
    2769           0 :                     *hour += 0;
    2770           0 :                     err = 0;
    2771           0 :                     pstr += 4;
    2772             :                 }
    2773           4 :                 if (strncmp(pstr, "PM", 2) == 0)
    2774             :                 {
    2775           0 :                     *hour += 12;
    2776           0 :                     err = 0;
    2777           0 :                     pstr += 2;
    2778             :                 }
    2779           4 :                 if (strncmp(pstr, "P.M.", 4) == 0)
    2780             :                 {
    2781           4 :                     *hour += 12;
    2782           4 :                     err = 0;
    2783           4 :                     pstr += 4;
    2784             :                 }
    2785           4 :                 break;
    2786           0 :             case 'r':
    2787           0 :                 pfmt++;
    2788           0 :                 tmp = pgtypes_alloc(strlen("%I:%M:%S %p") + strlen(pstr) + 1);
    2789           0 :                 if (!tmp)
    2790           0 :                     return 1;
    2791           0 :                 strcpy(tmp, "%I:%M:%S %p");
    2792           0 :                 strcat(tmp, pfmt);
    2793           0 :                 err = PGTYPEStimestamp_defmt_scan(&pstr, tmp, d, year, month, day, hour, minute, second, tz);
    2794           0 :                 free(tmp);
    2795           0 :                 return err;
    2796           0 :             case 'R':
    2797           0 :                 pfmt++;
    2798           0 :                 tmp = pgtypes_alloc(strlen("%H:%M") + strlen(pstr) + 1);
    2799           0 :                 if (!tmp)
    2800           0 :                     return 1;
    2801           0 :                 strcpy(tmp, "%H:%M");
    2802           0 :                 strcat(tmp, pfmt);
    2803           0 :                 err = PGTYPEStimestamp_defmt_scan(&pstr, tmp, d, year, month, day, hour, minute, second, tz);
    2804           0 :                 free(tmp);
    2805           0 :                 return err;
    2806           4 :             case 's':
    2807           4 :                 pfmt++;
    2808           4 :                 scan_type = PGTYPES_TYPE_UINT_LONG;
    2809           4 :                 err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt);
    2810             :                 /* number of seconds in scan_val.luint_val */
    2811             :                 {
    2812             :                     struct tm  *tms;
    2813           4 :                     time_t      et = (time_t) scan_val.luint_val;
    2814             : 
    2815           4 :                     tms = gmtime(&et);
    2816             : 
    2817           4 :                     if (tms)
    2818             :                     {
    2819           4 :                         *year = tms->tm_year + 1900;
    2820           4 :                         *month = tms->tm_mon + 1;
    2821           4 :                         *day = tms->tm_mday;
    2822           4 :                         *hour = tms->tm_hour;
    2823           4 :                         *minute = tms->tm_min;
    2824           4 :                         *second = tms->tm_sec;
    2825             :                     }
    2826             :                     else
    2827           0 :                         err = 1;
    2828             :                 }
    2829           4 :                 break;
    2830          60 :             case 'S':
    2831          60 :                 pfmt++;
    2832          60 :                 scan_type = PGTYPES_TYPE_UINT;
    2833          60 :                 err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt);
    2834          60 :                 *second = scan_val.uint_val;
    2835          60 :                 break;
    2836           0 :             case 't':
    2837           0 :                 pfmt++;
    2838           0 :                 if (*pstr == '\t')
    2839           0 :                     pstr++;
    2840             :                 else
    2841           0 :                     err = 1;
    2842           0 :                 break;
    2843           0 :             case 'T':
    2844           0 :                 pfmt++;
    2845           0 :                 tmp = pgtypes_alloc(strlen("%H:%M:%S") + strlen(pstr) + 1);
    2846           0 :                 if (!tmp)
    2847           0 :                     return 1;
    2848           0 :                 strcpy(tmp, "%H:%M:%S");
    2849           0 :                 strcat(tmp, pfmt);
    2850           0 :                 err = PGTYPEStimestamp_defmt_scan(&pstr, tmp, d, year, month, day, hour, minute, second, tz);
    2851           0 :                 free(tmp);
    2852           0 :                 return err;
    2853           0 :             case 'u':
    2854           0 :                 pfmt++;
    2855           0 :                 scan_type = PGTYPES_TYPE_UINT;
    2856           0 :                 err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt);
    2857           0 :                 if (scan_val.uint_val < 1 || scan_val.uint_val > 7)
    2858           0 :                     err = 1;
    2859           0 :                 break;
    2860           0 :             case 'U':
    2861           0 :                 pfmt++;
    2862           0 :                 scan_type = PGTYPES_TYPE_UINT;
    2863           0 :                 err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt);
    2864           0 :                 if (scan_val.uint_val > 53)
    2865           0 :                     err = 1;
    2866           0 :                 break;
    2867           0 :             case 'V':
    2868           0 :                 pfmt++;
    2869           0 :                 scan_type = PGTYPES_TYPE_UINT;
    2870           0 :                 err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt);
    2871           0 :                 if (scan_val.uint_val < 1 || scan_val.uint_val > 53)
    2872           0 :                     err = 1;
    2873           0 :                 break;
    2874           0 :             case 'w':
    2875           0 :                 pfmt++;
    2876           0 :                 scan_type = PGTYPES_TYPE_UINT;
    2877           0 :                 err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt);
    2878           0 :                 if (scan_val.uint_val > 6)
    2879           0 :                     err = 1;
    2880           0 :                 break;
    2881           0 :             case 'W':
    2882           0 :                 pfmt++;
    2883           0 :                 scan_type = PGTYPES_TYPE_UINT;
    2884           0 :                 err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt);
    2885           0 :                 if (scan_val.uint_val > 53)
    2886           0 :                     err = 1;
    2887           0 :                 break;
    2888           0 :             case 'x':
    2889             :             case 'X':
    2890             :                 /* XXX */
    2891           0 :                 break;
    2892          72 :             case 'Y':
    2893          72 :                 pfmt++;
    2894          72 :                 scan_type = PGTYPES_TYPE_UINT;
    2895          72 :                 err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt);
    2896          72 :                 *year = scan_val.uint_val;
    2897          72 :                 break;
    2898          32 :             case 'z':
    2899          32 :                 pfmt++;
    2900          32 :                 scan_type = PGTYPES_TYPE_STRING_MALLOCED;
    2901          32 :                 err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt);
    2902          32 :                 if (!err)
    2903             :                 {
    2904          32 :                     err = DecodeTimezone(scan_val.str_val, tz);
    2905          32 :                     free(scan_val.str_val);
    2906             :                 }
    2907          32 :                 break;
    2908          16 :             case 'Z':
    2909          16 :                 pfmt++;
    2910          16 :                 scan_type = PGTYPES_TYPE_STRING_MALLOCED;
    2911          16 :                 err = pgtypes_defmt_scan(&scan_val, scan_type, &pstr, pfmt);
    2912          16 :                 if (!err)
    2913             :                 {
    2914             :                     /*
    2915             :                      * XXX use DecodeSpecial instead?  Do we need strcasecmp
    2916             :                      * here?
    2917             :                      */
    2918          16 :                     err = 1;
    2919         800 :                     for (j = 0; j < szdatetktbl; j++)
    2920             :                     {
    2921        1440 :                         if ((datetktbl[j].type == TZ || datetktbl[j].type == DTZ) &&
    2922         640 :                             pg_strcasecmp(datetktbl[j].token,
    2923         640 :                                           scan_val.str_val) == 0)
    2924             :                         {
    2925          16 :                             *tz = -datetktbl[j].value;
    2926          16 :                             err = 0;
    2927          16 :                             break;
    2928             :                         }
    2929             :                     }
    2930          16 :                     free(scan_val.str_val);
    2931             :                 }
    2932          16 :                 break;
    2933           0 :             case '+':
    2934             :                 /* XXX */
    2935           0 :                 break;
    2936          16 :             case '%':
    2937          16 :                 pfmt++;
    2938          16 :                 if (*pstr == '%')
    2939          16 :                     pstr++;
    2940             :                 else
    2941           0 :                     err = 1;
    2942          16 :                 break;
    2943           4 :             default:
    2944           4 :                 err = 1;
    2945             :         }
    2946             :     }
    2947          88 :     if (!err)
    2948             :     {
    2949          84 :         if (*second < 0)
    2950          20 :             *second = 0;
    2951          84 :         if (*minute < 0)
    2952           0 :             *minute = 0;
    2953          84 :         if (*hour < 0)
    2954           0 :             *hour = 0;
    2955          84 :         if (*day < 0)
    2956             :         {
    2957           0 :             err = 1;
    2958           0 :             *day = 1;
    2959             :         }
    2960          84 :         if (*month < 0)
    2961             :         {
    2962           0 :             err = 1;
    2963           0 :             *month = 1;
    2964             :         }
    2965          84 :         if (*year < 0)
    2966             :         {
    2967           0 :             err = 1;
    2968           0 :             *year = 1970;
    2969             :         }
    2970             : 
    2971          84 :         if (*second > 59)
    2972             :         {
    2973           0 :             err = 1;
    2974           0 :             *second = 0;
    2975             :         }
    2976          84 :         if (*minute > 59)
    2977             :         {
    2978           0 :             err = 1;
    2979           0 :             *minute = 0;
    2980             :         }
    2981          84 :         if (*hour > 24 ||        /* test for > 24:00:00 */
    2982          84 :             (*hour == 24 && (*minute > 0 || *second > 0)))
    2983             :         {
    2984           0 :             err = 1;
    2985           0 :             *hour = 0;
    2986             :         }
    2987          84 :         if (*month > MONTHS_PER_YEAR)
    2988             :         {
    2989           0 :             err = 1;
    2990           0 :             *month = 1;
    2991             :         }
    2992          84 :         if (*day > day_tab[isleap(*year)][*month - 1])
    2993             :         {
    2994          16 :             *day = day_tab[isleap(*year)][*month - 1];
    2995          16 :             err = 1;
    2996             :         }
    2997             : 
    2998          84 :         tm.tm_sec = *second;
    2999          84 :         tm.tm_min = *minute;
    3000          84 :         tm.tm_hour = *hour;
    3001          84 :         tm.tm_mday = *day;
    3002          84 :         tm.tm_mon = *month;
    3003          84 :         tm.tm_year = *year;
    3004             : 
    3005          84 :         tm2timestamp(&tm, 0, tz, d);
    3006             :     }
    3007          88 :     return err;
    3008             : }
    3009             : 
    3010             : /* XXX: 1900 is compiled in as the base for years */

Generated by: LCOV version 1.14