LCOV - differential code coverage report
Current view: top level - src/interfaces/ecpg/pgtypeslib - datetime.c (source / functions) Coverage Total Hit UBC CBC
Current: Differential Code Coverage 16@8cea358b128 vs 17@8cea358b128 Lines: 82.4 % 284 234 50 234
Current Date: 2024-04-14 14:21:10 Functions: 90.9 % 11 10 1 10
Baseline: 16@8cea358b128 Branches: 72.5 % 167 121 46 121
Baseline Date: 2024-04-14 14:21:09 Line coverage date bins:
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed (240..) days: 82.4 % 284 234 50 234
Function coverage date bins:
(240..) days: 90.9 % 11 10 1 10
Branch coverage date bins:
(240..) days: 72.5 % 167 121 46 121

 Age         Owner                    Branch data    TLA  Line data    Source code
                                  1                 :                : /* src/interfaces/ecpg/pgtypeslib/datetime.c */
                                  2                 :                : 
                                  3                 :                : #include "postgres_fe.h"
                                  4                 :                : 
                                  5                 :                : #include <time.h>
                                  6                 :                : #include <ctype.h>
                                  7                 :                : #include <limits.h>
                                  8                 :                : 
                                  9                 :                : #include "dt.h"
                                 10                 :                : #include "pgtypes_date.h"
                                 11                 :                : #include "pgtypes_error.h"
                                 12                 :                : #include "pgtypeslib_extern.h"
                                 13                 :                : 
                                 14                 :                : date *
 6422 meskes@postgresql.or       15                 :CBC           1 : PGTYPESdate_new(void)
                                 16                 :                : {
                                 17                 :                :     date       *result;
                                 18                 :                : 
                                 19                 :              1 :     result = (date *) pgtypes_alloc(sizeof(date));
                                 20                 :                :     /* result can be NULL if we run out of memory */
                                 21                 :              1 :     return result;
                                 22                 :                : }
                                 23                 :                : 
                                 24                 :                : void
 6402 bruce@momjian.us           25                 :              1 : PGTYPESdate_free(date * d)
                                 26                 :                : {
 6422 meskes@postgresql.or       27                 :              1 :     free(d);
                                 28                 :              1 : }
                                 29                 :                : 
                                 30                 :                : date
 7523                            31                 :              6 : PGTYPESdate_from_timestamp(timestamp dt)
                                 32                 :                : {
                                 33                 :                :     date        dDate;
                                 34                 :                : 
 7559 bruce@momjian.us           35                 :              6 :     dDate = 0;                  /* suppress compiler warning */
                                 36                 :                : 
 6528 meskes@postgresql.or       37   [ +  -  +  - ]:              6 :     if (!TIMESTAMP_NOT_FINITE(dt))
                                 38                 :                :     {
                                 39                 :                :         /* Microseconds to days */
                                 40                 :              6 :         dDate = (dt / USECS_PER_DAY);
                                 41                 :                :     }
                                 42                 :                : 
 7686                            43                 :              6 :     return dDate;
                                 44                 :                : }
                                 45                 :                : 
                                 46                 :                : date
 7684                            47                 :             54 : PGTYPESdate_from_asc(char *str, char **endptr)
                                 48                 :                : {
                                 49                 :                :     date        dDate;
                                 50                 :                :     fsec_t      fsec;
                                 51                 :                :     struct tm   tt,
 7696                            52                 :             54 :                *tm = &tt;
                                 53                 :                :     int         dtype;
                                 54                 :                :     int         nf;
                                 55                 :                :     char       *field[MAXDATEFIELDS];
                                 56                 :                :     int         ftype[MAXDATEFIELDS];
                                 57                 :                :     char        lowstr[MAXDATELEN + MAXDATEFIELDS];
                                 58                 :                :     char       *realptr;
 7559 bruce@momjian.us           59         [ +  + ]:             54 :     char      **ptr = (endptr != NULL) ? endptr : &realptr;
                                 60                 :                : 
 2433 peter_e@gmx.net            61                 :             54 :     bool        EuroDates = false;
                                 62                 :                : 
 7677 meskes@postgresql.or       63                 :             54 :     errno = 0;
 3709 noah@leadboat.com          64         [ -  + ]:             54 :     if (strlen(str) > MAXDATELEN)
                                 65                 :                :     {
 7686 meskes@postgresql.or       66                 :UBC           0 :         errno = PGTYPES_DATE_BAD_DATE;
 7495                            67                 :              0 :         return INT_MIN;
                                 68                 :                :     }
                                 69                 :                : 
 5443 meskes@postgresql.or       70   [ +  +  +  + ]:CBC         107 :     if (ParseDateTime(str, lowstr, field, ftype, &nf, ptr) != 0 ||
 5995 bruce@momjian.us           71                 :             53 :         DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, EuroDates) != 0)
                                 72                 :                :     {
 7686 meskes@postgresql.or       73                 :              5 :         errno = PGTYPES_DATE_BAD_DATE;
 7495                            74                 :              5 :         return INT_MIN;
                                 75                 :                :     }
                                 76                 :                : 
 7696                            77      [ +  -  - ]:             49 :     switch (dtype)
                                 78                 :                :     {
                                 79                 :             49 :         case DTK_DATE:
                                 80                 :             49 :             break;
                                 81                 :                : 
 7696 meskes@postgresql.or       82                 :UBC           0 :         case DTK_EPOCH:
 5548                            83         [ #  # ]:              0 :             if (GetEpochTime(tm) < 0)
                                 84                 :                :             {
                                 85                 :              0 :                 errno = PGTYPES_DATE_BAD_DATE;
                                 86                 :              0 :                 return INT_MIN;
                                 87                 :                :             }
 7696                            88                 :              0 :             break;
                                 89                 :                : 
                                 90                 :              0 :         default:
 7686                            91                 :              0 :             errno = PGTYPES_DATE_BAD_DATE;
 7495                            92                 :              0 :             return INT_MIN;
                                 93                 :                :     }
                                 94                 :                : 
 7696 meskes@postgresql.or       95                 :CBC          49 :     dDate = (date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - date2j(2000, 1, 1));
                                 96                 :                : 
                                 97                 :             49 :     return dDate;
                                 98                 :                : }
                                 99                 :                : 
                                100                 :                : char *
 7523                           101                 :             95 : PGTYPESdate_to_asc(date dDate)
                                102                 :                : {
                                103                 :                :     struct tm   tt,
 7559 bruce@momjian.us          104                 :             95 :                *tm = &tt;
                                105                 :                :     char        buf[MAXDATELEN + 1];
                                106                 :             95 :     int         DateStyle = 1;
 2433 peter_e@gmx.net           107                 :             95 :     bool        EuroDates = false;
                                108                 :                : 
 6900 bruce@momjian.us          109                 :             95 :     j2date(dDate + date2j(2000, 1, 1), &(tm->tm_year), &(tm->tm_mon), &(tm->tm_mday));
 7696 meskes@postgresql.or      110                 :             95 :     EncodeDateOnly(tm, DateStyle, buf, EuroDates);
                                111                 :             95 :     return pgtypes_strdup(buf);
                                112                 :                : }
                                113                 :                : 
                                114                 :                : void
 7523                           115                 :              1 : PGTYPESdate_julmdy(date jd, int *mdy)
                                116                 :                : {
                                117                 :                :     int         y,
                                118                 :                :                 m,
                                119                 :                :                 d;
                                120                 :                : 
 7570                           121                 :              1 :     j2date((int) (jd + date2j(2000, 1, 1)), &y, &m, &d);
 7577                           122                 :              1 :     mdy[0] = m;
                                123                 :              1 :     mdy[1] = d;
                                124                 :              1 :     mdy[2] = y;
 7696                           125                 :              1 : }
                                126                 :                : 
                                127                 :                : void
 6756 bruce@momjian.us          128                 :              2 : PGTYPESdate_mdyjul(int *mdy, date * jdate)
                                129                 :                : {
                                130                 :                :     /* month is mdy[0] */
                                131                 :                :     /* day   is mdy[1] */
                                132                 :                :     /* year  is mdy[2] */
                                133                 :                : 
 7523 meskes@postgresql.or      134                 :              2 :     *jdate = (date) (date2j(mdy[2], mdy[0], mdy[1]) - date2j(2000, 1, 1));
 7696                           135                 :              2 : }
                                136                 :                : 
                                137                 :                : int
 7523                           138                 :             18 : PGTYPESdate_dayofweek(date dDate)
                                139                 :                : {
                                140                 :                :     /*
                                141                 :                :      * Sunday:  0 Monday:      1 Tuesday:     2 Wednesday:   3 Thursday: 4
                                142                 :                :      * Friday:      5 Saturday:    6
                                143                 :                :      */
 7497                           144                 :             18 :     return (int) (dDate + date2j(2000, 1, 1) + 1) % 7;
                                145                 :                : }
                                146                 :                : 
                                147                 :                : void
 6756 bruce@momjian.us          148                 :UBC           0 : PGTYPESdate_today(date * d)
                                149                 :                : {
                                150                 :                :     struct tm   ts;
                                151                 :                : 
 7686 meskes@postgresql.or      152                 :              0 :     GetCurrentDateTime(&ts);
 5548                           153         [ #  # ]:              0 :     if (errno == 0)
                                154                 :              0 :         *d = date2j(ts.tm_year, ts.tm_mon, ts.tm_mday) - date2j(2000, 1, 1);
 7695                           155                 :              0 : }
                                156                 :                : 
                                157                 :                : #define PGTYPES_DATE_NUM_MAX_DIGITS     20  /* should suffice for most
                                158                 :                :                                              * years... */
                                159                 :                : 
                                160                 :                : #define PGTYPES_FMTDATE_DAY_DIGITS_LZ       1   /* LZ means "leading zeroes" */
                                161                 :                : #define PGTYPES_FMTDATE_DOW_LITERAL_SHORT   2
                                162                 :                : #define PGTYPES_FMTDATE_MONTH_DIGITS_LZ     3
                                163                 :                : #define PGTYPES_FMTDATE_MONTH_LITERAL_SHORT 4
                                164                 :                : #define PGTYPES_FMTDATE_YEAR_DIGITS_SHORT   5
                                165                 :                : #define PGTYPES_FMTDATE_YEAR_DIGITS_LONG    6
                                166                 :                : 
                                167                 :                : int
 4501 meskes@postgresql.or      168                 :CBC          13 : PGTYPESdate_fmt_asc(date dDate, const char *fmtstring, char *outbuf)
                                169                 :                : {
                                170                 :                :     static struct
                                171                 :                :     {
                                172                 :                :         char       *format;
                                173                 :                :         int         component;
                                174                 :                :     }           mapping[] =
                                175                 :                :     {
                                176                 :                :         /*
                                177                 :                :          * format items have to be sorted according to their length, since the
                                178                 :                :          * first pattern that matches gets replaced by its value
                                179                 :                :          */
                                180                 :                :         {
                                181                 :                :             "ddd", PGTYPES_FMTDATE_DOW_LITERAL_SHORT
                                182                 :                :         },
                                183                 :                :         {
                                184                 :                :             "dd", PGTYPES_FMTDATE_DAY_DIGITS_LZ
                                185                 :                :         },
                                186                 :                :         {
                                187                 :                :             "mmm", PGTYPES_FMTDATE_MONTH_LITERAL_SHORT
                                188                 :                :         },
                                189                 :                :         {
                                190                 :                :             "mm", PGTYPES_FMTDATE_MONTH_DIGITS_LZ
                                191                 :                :         },
                                192                 :                :         {
                                193                 :                :             "yyyy", PGTYPES_FMTDATE_YEAR_DIGITS_LONG
                                194                 :                :         },
                                195                 :                :         {
                                196                 :                :             "yy", PGTYPES_FMTDATE_YEAR_DIGITS_SHORT
                                197                 :                :         },
                                198                 :                :         {
                                199                 :                :             NULL, 0
                                200                 :                :         }
                                201                 :                :     };
                                202                 :                : 
                                203                 :                :     union un_fmt_comb replace_val;
                                204                 :                :     int         replace_type;
                                205                 :                : 
                                206                 :                :     int         i;
                                207                 :                :     int         dow;
                                208                 :                :     char       *start_pattern;
                                209                 :                :     struct tm   tm;
                                210                 :                : 
                                211                 :                :     /* copy the string over */
 7686                           212                 :             13 :     strcpy(outbuf, fmtstring);
                                213                 :                : 
                                214                 :                :     /* get the date */
 6900 bruce@momjian.us          215                 :             13 :     j2date(dDate + date2j(2000, 1, 1), &(tm.tm_year), &(tm.tm_mon), &(tm.tm_mday));
 7686 meskes@postgresql.or      216                 :             13 :     dow = PGTYPESdate_dayofweek(dDate);
                                217                 :                : 
 7559 bruce@momjian.us          218         [ +  + ]:             91 :     for (i = 0; mapping[i].format != NULL; i++)
                                219                 :                :     {
                                220         [ +  + ]:            124 :         while ((start_pattern = strstr(outbuf, mapping[i].format)) != NULL)
                                221                 :                :         {
                                222   [ +  +  +  +  :             46 :             switch (mapping[i].component)
                                           +  +  - ]
                                223                 :                :             {
 7686 meskes@postgresql.or      224                 :              4 :                 case PGTYPES_FMTDATE_DOW_LITERAL_SHORT:
 7562                           225                 :              4 :                     replace_val.str_val = pgtypes_date_weekdays_short[dow];
                                226                 :              4 :                     replace_type = PGTYPES_TYPE_STRING_CONSTANT;
 7686                           227                 :              4 :                     break;
                                228                 :             14 :                 case PGTYPES_FMTDATE_DAY_DIGITS_LZ:
 7562                           229                 :             14 :                     replace_val.uint_val = tm.tm_mday;
                                230                 :             14 :                     replace_type = PGTYPES_TYPE_UINT_2_LZ;
 7686                           231                 :             14 :                     break;
                                232                 :              6 :                 case PGTYPES_FMTDATE_MONTH_LITERAL_SHORT:
 7559 bruce@momjian.us          233                 :              6 :                     replace_val.str_val = months[tm.tm_mon - 1];
 7562 meskes@postgresql.or      234                 :              6 :                     replace_type = PGTYPES_TYPE_STRING_CONSTANT;
 7686                           235                 :              6 :                     break;
                                236                 :              8 :                 case PGTYPES_FMTDATE_MONTH_DIGITS_LZ:
 7562                           237                 :              8 :                     replace_val.uint_val = tm.tm_mon;
                                238                 :              8 :                     replace_type = PGTYPES_TYPE_UINT_2_LZ;
 7686                           239                 :              8 :                     break;
                                240                 :              8 :                 case PGTYPES_FMTDATE_YEAR_DIGITS_LONG:
 7562                           241                 :              8 :                     replace_val.uint_val = tm.tm_year;
                                242                 :              8 :                     replace_type = PGTYPES_TYPE_UINT_4_LZ;
 7686                           243                 :              8 :                     break;
                                244                 :              6 :                 case PGTYPES_FMTDATE_YEAR_DIGITS_SHORT:
 6452                           245                 :              6 :                     replace_val.uint_val = tm.tm_year % 100;
 7562                           246                 :              6 :                     replace_type = PGTYPES_TYPE_UINT_2_LZ;
 7686                           247                 :              6 :                     break;
 7686 meskes@postgresql.or      248                 :UBC           0 :                 default:
                                249                 :                : 
                                250                 :                :                     /*
                                251                 :                :                      * should not happen, set something anyway
                                252                 :                :                      */
 7562                           253                 :              0 :                     replace_val.str_val = " ";
                                254                 :              0 :                     replace_type = PGTYPES_TYPE_STRING_CONSTANT;
                                255                 :                :             }
 7559 bruce@momjian.us          256   [ +  -  +  +  :CBC          46 :             switch (replace_type)
                                                 - ]
                                257                 :                :             {
 7562 meskes@postgresql.or      258                 :             10 :                 case PGTYPES_TYPE_STRING_MALLOCED:
                                259                 :                :                 case PGTYPES_TYPE_STRING_CONSTANT:
 3368 tgl@sss.pgh.pa.us         260                 :             10 :                     memcpy(start_pattern, replace_val.str_val,
                                261                 :             10 :                            strlen(replace_val.str_val));
 7559 bruce@momjian.us          262         [ -  + ]:             10 :                     if (replace_type == PGTYPES_TYPE_STRING_MALLOCED)
 7562 meskes@postgresql.or      263                 :UBC           0 :                         free(replace_val.str_val);
 7686 meskes@postgresql.or      264                 :CBC          10 :                     break;
 7562 meskes@postgresql.or      265                 :UBC           0 :                 case PGTYPES_TYPE_UINT:
                                266                 :                :                     {
 7559 bruce@momjian.us          267                 :              0 :                         char       *t = pgtypes_alloc(PGTYPES_DATE_NUM_MAX_DIGITS);
                                268                 :                : 
                                269         [ #  # ]:              0 :                         if (!t)
 7686 meskes@postgresql.or      270                 :              0 :                             return -1;
                                271                 :              0 :                         snprintf(t, PGTYPES_DATE_NUM_MAX_DIGITS,
                                272                 :                :                                  "%u", replace_val.uint_val);
 3368 tgl@sss.pgh.pa.us         273                 :              0 :                         memcpy(start_pattern, t, strlen(t));
 7686 meskes@postgresql.or      274                 :              0 :                         free(t);
                                275                 :                :                     }
                                276                 :              0 :                     break;
 7562 meskes@postgresql.or      277                 :CBC          28 :                 case PGTYPES_TYPE_UINT_2_LZ:
                                278                 :                :                     {
 7559 bruce@momjian.us          279                 :             28 :                         char       *t = pgtypes_alloc(PGTYPES_DATE_NUM_MAX_DIGITS);
                                280                 :                : 
                                281         [ -  + ]:             28 :                         if (!t)
 7686 meskes@postgresql.or      282                 :UBC           0 :                             return -1;
 7686 meskes@postgresql.or      283                 :CBC          28 :                         snprintf(t, PGTYPES_DATE_NUM_MAX_DIGITS,
                                284                 :                :                                  "%02u", replace_val.uint_val);
 3368 tgl@sss.pgh.pa.us         285                 :             28 :                         memcpy(start_pattern, t, strlen(t));
 7686 meskes@postgresql.or      286                 :             28 :                         free(t);
                                287                 :                :                     }
                                288                 :             28 :                     break;
 7562                           289                 :              8 :                 case PGTYPES_TYPE_UINT_4_LZ:
                                290                 :                :                     {
 7559 bruce@momjian.us          291                 :              8 :                         char       *t = pgtypes_alloc(PGTYPES_DATE_NUM_MAX_DIGITS);
                                292                 :                : 
                                293         [ -  + ]:              8 :                         if (!t)
 7686 meskes@postgresql.or      294                 :UBC           0 :                             return -1;
 7686 meskes@postgresql.or      295                 :CBC           8 :                         snprintf(t, PGTYPES_DATE_NUM_MAX_DIGITS,
                                296                 :                :                                  "%04u", replace_val.uint_val);
 3368 tgl@sss.pgh.pa.us         297                 :              8 :                         memcpy(start_pattern, t, strlen(t));
 7686 meskes@postgresql.or      298                 :              8 :                         free(t);
                                299                 :                :                     }
                                300                 :              8 :                     break;
 7686 meskes@postgresql.or      301                 :UBC           0 :                 default:
                                302                 :                : 
                                303                 :                :                     /*
                                304                 :                :                      * doesn't happen (we set replace_type to
                                305                 :                :                      * PGTYPES_TYPE_STRING_CONSTANT in case of an error above)
                                306                 :                :                      */
                                307                 :              0 :                     break;
                                308                 :                :             }
                                309                 :                :         }
                                310                 :                :     }
 7695 meskes@postgresql.or      311                 :CBC          13 :     return 0;
                                312                 :                : }
                                313                 :                : 
                                314                 :                : 
                                315                 :                : /*
                                316                 :                :  * PGTYPESdate_defmt_asc
                                317                 :                :  *
                                318                 :                :  * function works as follows:
                                319                 :                :  *   - first we analyze the parameters
                                320                 :                :  *   - if this is a special case with no delimiters, add delimiters
                                321                 :                :  *   - find the tokens. First we look for numerical values. If we have found
                                322                 :                :  *     less than 3 tokens, we check for the months' names and thereafter for
                                323                 :                :  *     the abbreviations of the months' names.
                                324                 :                :  *   - then we see which parameter should be the date, the month and the
                                325                 :                :  *     year and from these values we calculate the date
                                326                 :                :  */
                                327                 :                : 
                                328                 :                : #define PGTYPES_DATE_MONTH_MAXLENGTH        20  /* probably even less  :-) */
                                329                 :                : int
 2357 peter_e@gmx.net           330                 :             33 : PGTYPESdate_defmt_asc(date * d, const char *fmt, const char *str)
                                331                 :                : {
                                332                 :                :     /*
                                333                 :                :      * token[2] = { 4,6 } means that token 2 starts at position 4 and ends at
                                334                 :                :      * (including) position 6
                                335                 :                :      */
                                336                 :                :     int         token[3][2];
 7559 bruce@momjian.us          337                 :             33 :     int         token_values[3] = {-1, -1, -1};
                                338                 :                :     char       *fmt_token_order;
                                339                 :                :     char       *fmt_ystart,
                                340                 :                :                *fmt_mstart,
                                341                 :                :                *fmt_dstart;
                                342                 :                :     unsigned int i;
                                343                 :                :     int         reading_digit;
                                344                 :                :     int         token_count;
                                345                 :                :     char       *str_copy;
                                346                 :                :     struct tm   tm;
                                347                 :                : 
 6756                           348                 :             33 :     tm.tm_year = tm.tm_mon = tm.tm_mday = 0;    /* keep compiler quiet */
                                349                 :                : 
 7559                           350   [ +  -  +  -  :             33 :     if (!d || !str || !fmt)
                                              -  + ]
                                351                 :                :     {
 7686 meskes@postgresql.or      352                 :UBC           0 :         errno = PGTYPES_DATE_ERR_EARGS;
                                353                 :              0 :         return -1;
                                354                 :                :     }
                                355                 :                : 
                                356                 :                :     /* analyze the fmt string */
 7686 meskes@postgresql.or      357                 :CBC          33 :     fmt_ystart = strstr(fmt, "yy");
                                358                 :             33 :     fmt_mstart = strstr(fmt, "mm");
                                359                 :             33 :     fmt_dstart = strstr(fmt, "dd");
                                360                 :                : 
 7559 bruce@momjian.us          361   [ +  +  +  -  :             33 :     if (!fmt_ystart || !fmt_mstart || !fmt_dstart)
                                              -  + ]
                                362                 :                :     {
 7686 meskes@postgresql.or      363                 :              1 :         errno = PGTYPES_DATE_ERR_EARGS;
                                364                 :              1 :         return -1;
                                365                 :                :     }
                                366                 :                : 
 7559 bruce@momjian.us          367         [ +  + ]:             32 :     if (fmt_ystart < fmt_mstart)
                                368                 :                :     {
                                369                 :                :         /* y m */
                                370         [ -  + ]:              7 :         if (fmt_dstart < fmt_ystart)
                                371                 :                :         {
                                372                 :                :             /* d y m */
 7686 meskes@postgresql.or      373                 :UBC           0 :             fmt_token_order = "dym";
                                374                 :                :         }
 7559 bruce@momjian.us          375         [ +  - ]:CBC           7 :         else if (fmt_dstart > fmt_mstart)
                                376                 :                :         {
                                377                 :                :             /* y m d */
 7686 meskes@postgresql.or      378                 :              7 :             fmt_token_order = "ymd";
                                379                 :                :         }
                                380                 :                :         else
                                381                 :                :         {
                                382                 :                :             /* y d m */
 7686 meskes@postgresql.or      383                 :UBC           0 :             fmt_token_order = "ydm";
                                384                 :                :         }
                                385                 :                :     }
                                386                 :                :     else
                                387                 :                :     {
                                388                 :                :         /* fmt_ystart > fmt_mstart */
                                389                 :                :         /* m y */
 7559 bruce@momjian.us          390         [ +  + ]:CBC          25 :         if (fmt_dstart < fmt_mstart)
                                391                 :                :         {
                                392                 :                :             /* d m y */
 7686 meskes@postgresql.or      393                 :             11 :             fmt_token_order = "dmy";
                                394                 :                :         }
 7559 bruce@momjian.us          395         [ +  + ]:             14 :         else if (fmt_dstart > fmt_ystart)
                                396                 :                :         {
                                397                 :                :             /* m y d */
 7686 meskes@postgresql.or      398                 :              2 :             fmt_token_order = "myd";
                                399                 :                :         }
                                400                 :                :         else
                                401                 :                :         {
                                402                 :                :             /* m d y */
                                403                 :             12 :             fmt_token_order = "mdy";
                                404                 :                :         }
                                405                 :                :     }
                                406                 :                : 
                                407                 :                :     /*
                                408                 :                :      * handle the special cases where there is no delimiter between the
                                409                 :                :      * digits. If we see this:
                                410                 :                :      *
                                411                 :                :      * only digits, 6 or 8 bytes then it might be ddmmyy and ddmmyyyy (or
                                412                 :                :      * similar)
                                413                 :                :      *
                                414                 :                :      * we reduce it to a string with delimiters and continue processing
                                415                 :                :      */
                                416                 :                : 
                                417                 :                :     /* check if we have only digits */
                                418                 :             32 :     reading_digit = 1;
 7559 bruce@momjian.us          419         [ +  + ]:            118 :     for (i = 0; str[i]; i++)
                                420                 :                :     {
 7406 tgl@sss.pgh.pa.us         421         [ +  + ]:            109 :         if (!isdigit((unsigned char) str[i]))
                                422                 :                :         {
 7686 meskes@postgresql.or      423                 :             23 :             reading_digit = 0;
                                424                 :             23 :             break;
                                425                 :                :         }
                                426                 :                :     }
 7559 bruce@momjian.us          427         [ +  + ]:             32 :     if (reading_digit)
                                428                 :                :     {
                                429                 :                :         int         frag_length[3];
                                430                 :                :         int         target_pos;
                                431                 :                : 
 7686 meskes@postgresql.or      432                 :              9 :         i = strlen(str);
 7559 bruce@momjian.us          433   [ +  +  +  + ]:              9 :         if (i != 8 && i != 6)
                                434                 :                :         {
 7686 meskes@postgresql.or      435                 :              1 :             errno = PGTYPES_DATE_ERR_ENOSHORTDATE;
                                436                 :              1 :             return -1;
                                437                 :                :         }
                                438                 :                :         /* okay, this really is the special case */
                                439                 :                : 
                                440                 :                :         /*
                                441                 :                :          * as long as the string, one additional byte for the terminator and 2
                                442                 :                :          * for the delimiters between the 3 fields
                                443                 :                :          */
                                444                 :              8 :         str_copy = pgtypes_alloc(strlen(str) + 1 + 2);
 7559 bruce@momjian.us          445         [ -  + ]:              8 :         if (!str_copy)
 7686 meskes@postgresql.or      446                 :UBC           0 :             return -1;
                                447                 :                : 
                                448                 :                :         /* determine length of the fragments */
 7559 bruce@momjian.us          449         [ +  + ]:CBC           8 :         if (i == 6)
                                450                 :                :         {
                                451                 :              4 :             frag_length[0] = 2;
                                452                 :              4 :             frag_length[1] = 2;
                                453                 :              4 :             frag_length[2] = 2;
                                454                 :                :         }
                                455                 :                :         else
                                456                 :                :         {
                                457         [ +  + ]:              4 :             if (fmt_token_order[0] == 'y')
                                458                 :                :             {
                                459                 :              1 :                 frag_length[0] = 4;
                                460                 :              1 :                 frag_length[1] = 2;
                                461                 :              1 :                 frag_length[2] = 2;
                                462                 :                :             }
                                463         [ +  + ]:              3 :             else if (fmt_token_order[1] == 'y')
                                464                 :                :             {
                                465                 :              1 :                 frag_length[0] = 2;
                                466                 :              1 :                 frag_length[1] = 4;
                                467                 :              1 :                 frag_length[2] = 2;
                                468                 :                :             }
                                469                 :                :             else
                                470                 :                :             {
                                471                 :              2 :                 frag_length[0] = 2;
                                472                 :              2 :                 frag_length[1] = 2;
                                473                 :              2 :                 frag_length[2] = 4;
                                474                 :                :             }
                                475                 :                :         }
 7686 meskes@postgresql.or      476                 :              8 :         target_pos = 0;
                                477                 :                : 
                                478                 :                :         /*
                                479                 :                :          * XXX: Here we could calculate the positions of the tokens and save
                                480                 :                :          * the for loop down there where we again check with isdigit() for
                                481                 :                :          * digits.
                                482                 :                :          */
 7559 bruce@momjian.us          483         [ +  + ]:             32 :         for (i = 0; i < 3; i++)
                                484                 :                :         {
                                485                 :             24 :             int         start_pos = 0;
                                486                 :                : 
                                487         [ +  + ]:             24 :             if (i >= 1)
                                488                 :             16 :                 start_pos += frag_length[0];
                                489         [ +  + ]:             24 :             if (i == 2)
                                490                 :              8 :                 start_pos += frag_length[1];
                                491                 :                : 
 7686 meskes@postgresql.or      492                 :             24 :             strncpy(str_copy + target_pos, str + start_pos,
 7559 bruce@momjian.us          493                 :             24 :                     frag_length[i]);
 7686 meskes@postgresql.or      494                 :             24 :             target_pos += frag_length[i];
 7559 bruce@momjian.us          495         [ +  + ]:             24 :             if (i != 2)
                                496                 :                :             {
 7686 meskes@postgresql.or      497                 :             16 :                 str_copy[target_pos] = ' ';
                                498                 :             16 :                 target_pos++;
                                499                 :                :             }
                                500                 :                :         }
                                501                 :              8 :         str_copy[target_pos] = '\0';
                                502                 :                :     }
                                503                 :                :     else
                                504                 :                :     {
                                505                 :             23 :         str_copy = pgtypes_strdup(str);
 7559 bruce@momjian.us          506         [ -  + ]:             23 :         if (!str_copy)
 7686 meskes@postgresql.or      507                 :UBC           0 :             return -1;
                                508                 :                : 
                                509                 :                :         /* convert the whole string to lower case */
 7559 bruce@momjian.us          510         [ +  + ]:CBC         444 :         for (i = 0; str_copy[i]; i++)
 7282 tgl@sss.pgh.pa.us         511                 :            421 :             str_copy[i] = (char) pg_tolower((unsigned char) str_copy[i]);
                                512                 :                :     }
                                513                 :                : 
                                514                 :                :     /* look for numerical tokens */
 7686 meskes@postgresql.or      515                 :             31 :     reading_digit = 0;
 7559 bruce@momjian.us          516                 :             31 :     token_count = 0;
                                517         [ +  + ]:            524 :     for (i = 0; i < strlen(str_copy); i++)
                                518                 :                :     {
 7406 tgl@sss.pgh.pa.us         519   [ +  +  +  + ]:            493 :         if (!isdigit((unsigned char) str_copy[i]) && reading_digit)
                                520                 :                :         {
                                521                 :                :             /* the token is finished */
 7559 bruce@momjian.us          522                 :             53 :             token[token_count][1] = i - 1;
 7686 meskes@postgresql.or      523                 :             53 :             reading_digit = 0;
                                524                 :             53 :             token_count++;
                                525                 :                :         }
 7406 tgl@sss.pgh.pa.us         526   [ +  +  +  + ]:            440 :         else if (isdigit((unsigned char) str_copy[i]) && !reading_digit)
                                527                 :                :         {
                                528                 :                :             /* we have found a token */
 7686 meskes@postgresql.or      529                 :             79 :             token[token_count][0] = i;
                                530                 :             79 :             reading_digit = 1;
                                531                 :                :         }
                                532                 :                :     }
                                533                 :                : 
                                534                 :                :     /*
                                535                 :                :      * we're at the end of the input string, but maybe we are still reading a
                                536                 :                :      * number...
                                537                 :                :      */
 7559 bruce@momjian.us          538         [ +  + ]:             31 :     if (reading_digit)
                                539                 :                :     {
                                540                 :             26 :         token[token_count][1] = i - 1;
 7686 meskes@postgresql.or      541                 :             26 :         token_count++;
                                542                 :                :     }
                                543                 :                : 
                                544                 :                : 
 7559 bruce@momjian.us          545         [ +  + ]:             31 :     if (token_count < 2)
                                546                 :                :     {
                                547                 :                :         /*
                                548                 :                :          * not all tokens found, no way to find 2 missing tokens with string
                                549                 :                :          * matches
                                550                 :                :          */
 7686 meskes@postgresql.or      551                 :              1 :         free(str_copy);
 6452                           552                 :              1 :         errno = PGTYPES_DATE_ERR_ENOSHORTDATE;
 7686                           553                 :              1 :         return -1;
                                554                 :                :     }
                                555                 :                : 
 7559 bruce@momjian.us          556         [ +  + ]:             30 :     if (token_count != 3)
                                557                 :                :     {
                                558                 :                :         /*
                                559                 :                :          * not all tokens found but we may find another one with string
                                560                 :                :          * matches by testing for the months names and months abbreviations
                                561                 :                :          */
                                562                 :             12 :         char       *month_lower_tmp = pgtypes_alloc(PGTYPES_DATE_MONTH_MAXLENGTH);
                                563                 :                :         char       *start_pos;
                                564                 :                :         int         j;
                                565                 :                :         int         offset;
                                566                 :             12 :         int         found = 0;
                                567                 :                :         char      **list;
                                568                 :                : 
                                569         [ -  + ]:             12 :         if (!month_lower_tmp)
                                570                 :                :         {
                                571                 :                :             /* free variables we alloc'ed before */
 7686 meskes@postgresql.or      572                 :UBC           0 :             free(str_copy);
                                573                 :              0 :             return -1;
                                574                 :                :         }
 7686 meskes@postgresql.or      575                 :CBC          12 :         list = pgtypes_date_months;
 7559 bruce@momjian.us          576         [ +  - ]:            184 :         for (i = 0; list[i]; i++)
                                577                 :                :         {
                                578         [ +  - ]:           1117 :             for (j = 0; j < PGTYPES_DATE_MONTH_MAXLENGTH; j++)
                                579                 :                :             {
 7282 tgl@sss.pgh.pa.us         580                 :           1117 :                 month_lower_tmp[j] = (char) pg_tolower((unsigned char) list[i][j]);
 7559 bruce@momjian.us          581         [ +  + ]:           1117 :                 if (!month_lower_tmp[j])
                                582                 :                :                 {
                                583                 :                :                     /* properly terminated */
 7686 meskes@postgresql.or      584                 :            184 :                     break;
                                585                 :                :                 }
                                586                 :                :             }
 7559 bruce@momjian.us          587         [ +  + ]:            184 :             if ((start_pos = strstr(str_copy, month_lower_tmp)))
                                588                 :                :             {
 7686 meskes@postgresql.or      589                 :             12 :                 offset = start_pos - str_copy;
                                590                 :                : 
                                591                 :                :                 /*
                                592                 :                :                  * sort the new token into the numeric tokens, shift them if
                                593                 :                :                  * necessary
                                594                 :                :                  */
 7559 bruce@momjian.us          595         [ +  + ]:             12 :                 if (offset < token[0][0])
                                596                 :                :                 {
 7686 meskes@postgresql.or      597                 :              6 :                     token[2][0] = token[1][0];
                                598                 :              6 :                     token[2][1] = token[1][1];
                                599                 :              6 :                     token[1][0] = token[0][0];
                                600                 :              6 :                     token[1][1] = token[0][1];
                                601                 :              6 :                     token_count = 0;
                                602                 :                :                 }
 7559 bruce@momjian.us          603         [ +  - ]:              6 :                 else if (offset < token[1][0])
                                604                 :                :                 {
 7686 meskes@postgresql.or      605                 :              6 :                     token[2][0] = token[1][0];
                                606                 :              6 :                     token[2][1] = token[1][1];
                                607                 :              6 :                     token_count = 1;
                                608                 :                :                 }
                                609                 :                :                 else
 7559 bruce@momjian.us          610                 :UBC           0 :                     token_count = 2;
 7686 meskes@postgresql.or      611                 :CBC          12 :                 token[token_count][0] = offset;
                                612                 :             12 :                 token[token_count][1] = offset + strlen(month_lower_tmp) - 1;
                                613                 :                : 
                                614                 :                :                 /*
                                615                 :                :                  * the value is the index of the month in the array of months
                                616                 :                :                  * + 1 (January is month 0)
                                617                 :                :                  */
 7559 bruce@momjian.us          618                 :             12 :                 token_values[token_count] = i + 1;
 7686 meskes@postgresql.or      619                 :             12 :                 found = 1;
                                620                 :             12 :                 break;
                                621                 :                :             }
                                622                 :                : 
                                623                 :                :             /*
                                624                 :                :              * evil[tm] hack: if we read the pgtypes_date_months and haven't
                                625                 :                :              * found a match, reset list to point to months (abbreviations)
                                626                 :                :              * and reset the counter variable i
                                627                 :                :              */
 7559 bruce@momjian.us          628         [ +  + ]:            172 :             if (list == pgtypes_date_months)
                                629                 :                :             {
                                630         [ +  + ]:            118 :                 if (list[i + 1] == NULL)
                                631                 :                :                 {
 7684 meskes@postgresql.or      632                 :              6 :                     list = months;
 7686                           633                 :              6 :                     i = -1;
                                634                 :                :                 }
                                635                 :                :             }
                                636                 :                :         }
 7559 bruce@momjian.us          637         [ -  + ]:             12 :         if (!found)
                                638                 :                :         {
 7686 meskes@postgresql.or      639                 :UBC           0 :             free(month_lower_tmp);
                                640                 :              0 :             free(str_copy);
                                641                 :              0 :             errno = PGTYPES_DATE_ERR_ENOTDMY;
                                642                 :              0 :             return -1;
                                643                 :                :         }
                                644                 :                : 
                                645                 :                :         /*
                                646                 :                :          * here we found a month. token[token_count] and
                                647                 :                :          * token_values[token_count] reflect the month's details.
                                648                 :                :          *
                                649                 :                :          * only the month can be specified with a literal. Here we can do a
                                650                 :                :          * quick check if the month is at the right position according to the
                                651                 :                :          * format string because we can check if the token that we expect to
                                652                 :                :          * be the month is at the position of the only token that already has
                                653                 :                :          * a value. If we wouldn't check here we could say "December 4 1990"
                                654                 :                :          * with a fmt string of "dd mm yy" for 12 April 1990.
                                655                 :                :          */
 7559 bruce@momjian.us          656         [ -  + ]:CBC          12 :         if (fmt_token_order[token_count] != 'm')
                                657                 :                :         {
                                658                 :                :             /* deal with the error later on */
 7686 meskes@postgresql.or      659                 :UBC           0 :             token_values[token_count] = -1;
                                660                 :                :         }
 7686 meskes@postgresql.or      661                 :CBC          12 :         free(month_lower_tmp);
                                662                 :                :     }
                                663                 :                : 
                                664                 :                :     /* terminate the tokens with ASCII-0 and get their values */
 7559 bruce@momjian.us          665         [ +  + ]:            120 :     for (i = 0; i < 3; i++)
                                666                 :                :     {
 7686 meskes@postgresql.or      667                 :             90 :         *(str_copy + token[i][1] + 1) = '\0';
                                668                 :                :         /* A month already has a value set, check for token_value == -1 */
 7559 bruce@momjian.us          669         [ +  + ]:             90 :         if (token_values[i] == -1)
                                670                 :                :         {
 7686 meskes@postgresql.or      671                 :             78 :             errno = 0;
                                672                 :             78 :             token_values[i] = strtol(str_copy + token[i][0], (char **) NULL, 10);
                                673                 :                :             /* strtol sets errno in case of an error */
 7559 bruce@momjian.us          674         [ -  + ]:             78 :             if (errno)
 7686 meskes@postgresql.or      675                 :UBC           0 :                 token_values[i] = -1;
                                676                 :                :         }
 7559 bruce@momjian.us          677         [ +  + ]:CBC          90 :         if (fmt_token_order[i] == 'd')
 7686 meskes@postgresql.or      678                 :             30 :             tm.tm_mday = token_values[i];
 7559 bruce@momjian.us          679         [ +  + ]:             60 :         else if (fmt_token_order[i] == 'm')
 7686 meskes@postgresql.or      680                 :             30 :             tm.tm_mon = token_values[i];
 7559 bruce@momjian.us          681         [ +  - ]:             30 :         else if (fmt_token_order[i] == 'y')
 7686 meskes@postgresql.or      682                 :             30 :             tm.tm_year = token_values[i];
                                683                 :                :     }
                                684                 :             30 :     free(str_copy);
                                685                 :                : 
                                686   [ +  -  +  + ]:             30 :     if (tm.tm_mday < 1 || tm.tm_mday > 31)
                                687                 :                :     {
                                688                 :              1 :         errno = PGTYPES_DATE_BAD_DAY;
                                689                 :              1 :         return -1;
                                690                 :                :     }
                                691                 :                : 
 6842 bruce@momjian.us          692   [ +  -  +  + ]:             29 :     if (tm.tm_mon < 1 || tm.tm_mon > MONTHS_PER_YEAR)
                                693                 :                :     {
 7686 meskes@postgresql.or      694                 :              1 :         errno = PGTYPES_DATE_BAD_MONTH;
                                695                 :              1 :         return -1;
                                696                 :                :     }
                                697                 :                : 
 7559 bruce@momjian.us          698   [ -  +  -  -  :             28 :     if (tm.tm_mday == 31 && (tm.tm_mon == 4 || tm.tm_mon == 6 || tm.tm_mon == 9 || tm.tm_mon == 11))
                                     -  -  -  -  -  
                                                 - ]
                                699                 :                :     {
 7686 meskes@postgresql.or      700                 :UBC           0 :         errno = PGTYPES_DATE_BAD_DAY;
                                701                 :              0 :         return -1;
                                702                 :                :     }
                                703                 :                : 
 7686 meskes@postgresql.or      704   [ +  +  -  + ]:CBC          28 :     if (tm.tm_mon == 2 && tm.tm_mday > 29)
                                705                 :                :     {
 7686 meskes@postgresql.or      706                 :UBC           0 :         errno = PGTYPES_DATE_BAD_DAY;
                                707                 :              0 :         return -1;
                                708                 :                :     }
                                709                 :                : 
 7686 meskes@postgresql.or      710                 :CBC          28 :     *d = date2j(tm.tm_year, tm.tm_mon, tm.tm_mday) - date2j(2000, 1, 1);
                                711                 :                : 
 7695                           712                 :             28 :     return 0;
                                713                 :                : }
        

Generated by: LCOV version 2.1-beta2-3-g6141622