LCOV - code coverage report
Current view: top level - src/interfaces/ecpg/pgtypeslib - datetime.c (source / functions) Coverage Total Hit
Test: PostgreSQL 20devel Lines: 82.4 % 284 234
Test Date: 2026-07-25 22:15:46 Functions: 90.9 % 11 10
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 72.5 % 167 121

             Branch data     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 *
      15                 :           2 : PGTYPESdate_new(void)
      16                 :             : {
      17                 :             :     date       *result;
      18                 :             : 
      19                 :           2 :     result = (date *) pgtypes_alloc(sizeof(date));
      20                 :             :     /* result can be NULL if we run out of memory */
      21                 :           2 :     return result;
      22                 :             : }
      23                 :             : 
      24                 :             : void
      25                 :           2 : PGTYPESdate_free(date * d)
      26                 :             : {
      27                 :           2 :     free(d);
      28                 :           2 : }
      29                 :             : 
      30                 :             : date
      31                 :          12 : PGTYPESdate_from_timestamp(timestamp dt)
      32                 :             : {
      33                 :             :     date        dDate;
      34                 :             : 
      35                 :          12 :     dDate = 0;                  /* suppress compiler warning */
      36                 :             : 
      37   [ +  -  +  - ]:          12 :     if (!TIMESTAMP_NOT_FINITE(dt))
      38                 :             :     {
      39                 :             :         /* Microseconds to days */
      40                 :          12 :         dDate = (dt / USECS_PER_DAY);
      41                 :             :     }
      42                 :             : 
      43                 :          12 :     return dDate;
      44                 :             : }
      45                 :             : 
      46                 :             : date
      47                 :         108 : PGTYPESdate_from_asc(char *str, char **endptr)
      48                 :             : {
      49                 :             :     date        dDate;
      50                 :             :     fsec_t      fsec;
      51                 :             :     struct tm   tt,
      52                 :         108 :                *tm = &tt;
      53                 :             :     int         dtype;
      54                 :             :     int         nf;
      55                 :             :     char       *field[MAXDATEFIELDS];
      56                 :             :     int         ftype[MAXDATEFIELDS];
      57                 :             :     char        lowstr[MAXDATELEN + MAXDATEFIELDS];
      58                 :             :     char       *realptr;
      59         [ +  + ]:         108 :     char      **ptr = (endptr != NULL) ? endptr : &realptr;
      60                 :             : 
      61                 :         108 :     bool        EuroDates = false;
      62                 :             : 
      63                 :         108 :     errno = 0;
      64         [ -  + ]:         108 :     if (strlen(str) > MAXDATELEN)
      65                 :             :     {
      66                 :           0 :         errno = PGTYPES_DATE_BAD_DATE;
      67                 :           0 :         return INT_MIN;
      68                 :             :     }
      69                 :             : 
      70   [ +  +  +  + ]:         214 :     if (ParseDateTime(str, lowstr, field, ftype, &nf, ptr) != 0 ||
      71                 :         106 :         DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, EuroDates) != 0)
      72                 :             :     {
      73                 :          10 :         errno = PGTYPES_DATE_BAD_DATE;
      74                 :          10 :         return INT_MIN;
      75                 :             :     }
      76                 :             : 
      77      [ +  -  - ]:          98 :     switch (dtype)
      78                 :             :     {
      79                 :          98 :         case DTK_DATE:
      80                 :          98 :             break;
      81                 :             : 
      82                 :           0 :         case DTK_EPOCH:
      83         [ #  # ]:           0 :             if (GetEpochTime(tm) < 0)
      84                 :             :             {
      85                 :           0 :                 errno = PGTYPES_DATE_BAD_DATE;
      86                 :           0 :                 return INT_MIN;
      87                 :             :             }
      88                 :           0 :             break;
      89                 :             : 
      90                 :           0 :         default:
      91                 :           0 :             errno = PGTYPES_DATE_BAD_DATE;
      92                 :           0 :             return INT_MIN;
      93                 :             :     }
      94                 :             : 
      95                 :          98 :     dDate = (date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - date2j(2000, 1, 1));
      96                 :             : 
      97                 :          98 :     return dDate;
      98                 :             : }
      99                 :             : 
     100                 :             : char *
     101                 :         190 : PGTYPESdate_to_asc(date dDate)
     102                 :             : {
     103                 :             :     struct tm   tt,
     104                 :         190 :                *tm = &tt;
     105                 :             :     char        buf[MAXDATELEN + 1];
     106                 :         190 :     int         DateStyle = 1;
     107                 :         190 :     bool        EuroDates = false;
     108                 :             : 
     109                 :         190 :     j2date(dDate + date2j(2000, 1, 1), &(tm->tm_year), &(tm->tm_mon), &(tm->tm_mday));
     110                 :         190 :     EncodeDateOnly(tm, DateStyle, buf, EuroDates);
     111                 :         190 :     return pgtypes_strdup(buf);
     112                 :             : }
     113                 :             : 
     114                 :             : void
     115                 :           2 : PGTYPESdate_julmdy(date jd, int *mdy)
     116                 :             : {
     117                 :             :     int         y,
     118                 :             :                 m,
     119                 :             :                 d;
     120                 :             : 
     121                 :           2 :     j2date((int) (jd + date2j(2000, 1, 1)), &y, &m, &d);
     122                 :           2 :     mdy[0] = m;
     123                 :           2 :     mdy[1] = d;
     124                 :           2 :     mdy[2] = y;
     125                 :           2 : }
     126                 :             : 
     127                 :             : void
     128                 :           4 : PGTYPESdate_mdyjul(int *mdy, date * jdate)
     129                 :             : {
     130                 :             :     /* month is mdy[0] */
     131                 :             :     /* day   is mdy[1] */
     132                 :             :     /* year  is mdy[2] */
     133                 :             : 
     134                 :           4 :     *jdate = (date) (date2j(mdy[2], mdy[0], mdy[1]) - date2j(2000, 1, 1));
     135                 :           4 : }
     136                 :             : 
     137                 :             : int
     138                 :          36 : PGTYPESdate_dayofweek(date dDate)
     139                 :             : {
     140                 :             :     /*
     141                 :             :      * Sunday:  0 Monday:      1 Tuesday:     2 Wednesday:   3 Thursday: 4
     142                 :             :      * Friday:      5 Saturday:    6
     143                 :             :      */
     144                 :          36 :     return (int) (dDate + date2j(2000, 1, 1) + 1) % 7;
     145                 :             : }
     146                 :             : 
     147                 :             : void
     148                 :           0 : PGTYPESdate_today(date * d)
     149                 :             : {
     150                 :             :     struct tm   ts;
     151                 :             : 
     152                 :           0 :     GetCurrentDateTime(&ts);
     153         [ #  # ]:           0 :     if (errno == 0)
     154                 :           0 :         *d = date2j(ts.tm_year, ts.tm_mon, ts.tm_mday) - date2j(2000, 1, 1);
     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
     168                 :          26 : 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 */
     212                 :          26 :     strcpy(outbuf, fmtstring);
     213                 :             : 
     214                 :             :     /* get the date */
     215                 :          26 :     j2date(dDate + date2j(2000, 1, 1), &(tm.tm_year), &(tm.tm_mon), &(tm.tm_mday));
     216                 :          26 :     dow = PGTYPESdate_dayofweek(dDate);
     217                 :             : 
     218         [ +  + ]:         182 :     for (i = 0; mapping[i].format != NULL; i++)
     219                 :             :     {
     220         [ +  + ]:         248 :         while ((start_pattern = strstr(outbuf, mapping[i].format)) != NULL)
     221                 :             :         {
     222   [ +  +  +  +  :          92 :             switch (mapping[i].component)
                +  +  - ]
     223                 :             :             {
     224                 :           8 :                 case PGTYPES_FMTDATE_DOW_LITERAL_SHORT:
     225                 :           8 :                     replace_val.str_val = pgtypes_date_weekdays_short[dow];
     226                 :           8 :                     replace_type = PGTYPES_TYPE_STRING_CONSTANT;
     227                 :           8 :                     break;
     228                 :          28 :                 case PGTYPES_FMTDATE_DAY_DIGITS_LZ:
     229                 :          28 :                     replace_val.uint_val = tm.tm_mday;
     230                 :          28 :                     replace_type = PGTYPES_TYPE_UINT_2_LZ;
     231                 :          28 :                     break;
     232                 :          12 :                 case PGTYPES_FMTDATE_MONTH_LITERAL_SHORT:
     233                 :          12 :                     replace_val.str_val = months[tm.tm_mon - 1];
     234                 :          12 :                     replace_type = PGTYPES_TYPE_STRING_CONSTANT;
     235                 :          12 :                     break;
     236                 :          16 :                 case PGTYPES_FMTDATE_MONTH_DIGITS_LZ:
     237                 :          16 :                     replace_val.uint_val = tm.tm_mon;
     238                 :          16 :                     replace_type = PGTYPES_TYPE_UINT_2_LZ;
     239                 :          16 :                     break;
     240                 :          16 :                 case PGTYPES_FMTDATE_YEAR_DIGITS_LONG:
     241                 :          16 :                     replace_val.uint_val = tm.tm_year;
     242                 :          16 :                     replace_type = PGTYPES_TYPE_UINT_4_LZ;
     243                 :          16 :                     break;
     244                 :          12 :                 case PGTYPES_FMTDATE_YEAR_DIGITS_SHORT:
     245                 :          12 :                     replace_val.uint_val = tm.tm_year % 100;
     246                 :          12 :                     replace_type = PGTYPES_TYPE_UINT_2_LZ;
     247                 :          12 :                     break;
     248                 :           0 :                 default:
     249                 :             : 
     250                 :             :                     /*
     251                 :             :                      * should not happen, set something anyway
     252                 :             :                      */
     253                 :           0 :                     replace_val.str_val = " ";
     254                 :           0 :                     replace_type = PGTYPES_TYPE_STRING_CONSTANT;
     255                 :             :             }
     256   [ +  -  +  +  :          92 :             switch (replace_type)
                      - ]
     257                 :             :             {
     258                 :          20 :                 case PGTYPES_TYPE_STRING_MALLOCED:
     259                 :             :                 case PGTYPES_TYPE_STRING_CONSTANT:
     260                 :          20 :                     memcpy(start_pattern, replace_val.str_val,
     261                 :          20 :                            strlen(replace_val.str_val));
     262         [ -  + ]:          20 :                     if (replace_type == PGTYPES_TYPE_STRING_MALLOCED)
     263                 :           0 :                         free(replace_val.str_val);
     264                 :          20 :                     break;
     265                 :           0 :                 case PGTYPES_TYPE_UINT:
     266                 :             :                     {
     267                 :           0 :                         char       *t = pgtypes_alloc(PGTYPES_DATE_NUM_MAX_DIGITS);
     268                 :             : 
     269         [ #  # ]:           0 :                         if (!t)
     270                 :           0 :                             return -1;
     271                 :           0 :                         snprintf(t, PGTYPES_DATE_NUM_MAX_DIGITS,
     272                 :             :                                  "%u", replace_val.uint_val);
     273                 :           0 :                         memcpy(start_pattern, t, strlen(t));
     274                 :           0 :                         free(t);
     275                 :             :                     }
     276                 :           0 :                     break;
     277                 :          56 :                 case PGTYPES_TYPE_UINT_2_LZ:
     278                 :             :                     {
     279                 :          56 :                         char       *t = pgtypes_alloc(PGTYPES_DATE_NUM_MAX_DIGITS);
     280                 :             : 
     281         [ -  + ]:          56 :                         if (!t)
     282                 :           0 :                             return -1;
     283                 :          56 :                         snprintf(t, PGTYPES_DATE_NUM_MAX_DIGITS,
     284                 :             :                                  "%02u", replace_val.uint_val);
     285                 :          56 :                         memcpy(start_pattern, t, strlen(t));
     286                 :          56 :                         free(t);
     287                 :             :                     }
     288                 :          56 :                     break;
     289                 :          16 :                 case PGTYPES_TYPE_UINT_4_LZ:
     290                 :             :                     {
     291                 :          16 :                         char       *t = pgtypes_alloc(PGTYPES_DATE_NUM_MAX_DIGITS);
     292                 :             : 
     293         [ -  + ]:          16 :                         if (!t)
     294                 :           0 :                             return -1;
     295                 :          16 :                         snprintf(t, PGTYPES_DATE_NUM_MAX_DIGITS,
     296                 :             :                                  "%04u", replace_val.uint_val);
     297                 :          16 :                         memcpy(start_pattern, t, strlen(t));
     298                 :          16 :                         free(t);
     299                 :             :                     }
     300                 :          16 :                     break;
     301                 :           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                 :             :     }
     311                 :          26 :     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
     330                 :          66 : 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];
     337                 :          66 :     int         token_values[3] = {-1, -1, -1};
     338                 :             :     const char *fmt_token_order;
     339                 :             :     const 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                 :             : 
     348                 :          66 :     tm.tm_year = tm.tm_mon = tm.tm_mday = 0;    /* keep compiler quiet */
     349                 :             : 
     350   [ +  -  +  -  :          66 :     if (!d || !str || !fmt)
                   -  + ]
     351                 :             :     {
     352                 :           0 :         errno = PGTYPES_DATE_ERR_EARGS;
     353                 :           0 :         return -1;
     354                 :             :     }
     355                 :             : 
     356                 :             :     /* analyze the fmt string */
     357                 :          66 :     fmt_ystart = strstr(fmt, "yy");
     358                 :          66 :     fmt_mstart = strstr(fmt, "mm");
     359                 :          66 :     fmt_dstart = strstr(fmt, "dd");
     360                 :             : 
     361   [ +  +  +  -  :          66 :     if (!fmt_ystart || !fmt_mstart || !fmt_dstart)
                   -  + ]
     362                 :             :     {
     363                 :           2 :         errno = PGTYPES_DATE_ERR_EARGS;
     364                 :           2 :         return -1;
     365                 :             :     }
     366                 :             : 
     367         [ +  + ]:          64 :     if (fmt_ystart < fmt_mstart)
     368                 :             :     {
     369                 :             :         /* y m */
     370         [ -  + ]:          14 :         if (fmt_dstart < fmt_ystart)
     371                 :             :         {
     372                 :             :             /* d y m */
     373                 :           0 :             fmt_token_order = "dym";
     374                 :             :         }
     375         [ +  - ]:          14 :         else if (fmt_dstart > fmt_mstart)
     376                 :             :         {
     377                 :             :             /* y m d */
     378                 :          14 :             fmt_token_order = "ymd";
     379                 :             :         }
     380                 :             :         else
     381                 :             :         {
     382                 :             :             /* y d m */
     383                 :           0 :             fmt_token_order = "ydm";
     384                 :             :         }
     385                 :             :     }
     386                 :             :     else
     387                 :             :     {
     388                 :             :         /* fmt_ystart > fmt_mstart */
     389                 :             :         /* m y */
     390         [ +  + ]:          50 :         if (fmt_dstart < fmt_mstart)
     391                 :             :         {
     392                 :             :             /* d m y */
     393                 :          22 :             fmt_token_order = "dmy";
     394                 :             :         }
     395         [ +  + ]:          28 :         else if (fmt_dstart > fmt_ystart)
     396                 :             :         {
     397                 :             :             /* m y d */
     398                 :           4 :             fmt_token_order = "myd";
     399                 :             :         }
     400                 :             :         else
     401                 :             :         {
     402                 :             :             /* m d y */
     403                 :          24 :             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                 :          64 :     reading_digit = 1;
     419         [ +  + ]:         236 :     for (i = 0; str[i]; i++)
     420                 :             :     {
     421         [ +  + ]:         218 :         if (!isdigit((unsigned char) str[i]))
     422                 :             :         {
     423                 :          46 :             reading_digit = 0;
     424                 :          46 :             break;
     425                 :             :         }
     426                 :             :     }
     427         [ +  + ]:          64 :     if (reading_digit)
     428                 :             :     {
     429                 :             :         int         frag_length[3];
     430                 :             :         int         target_pos;
     431                 :             : 
     432                 :          18 :         i = strlen(str);
     433   [ +  +  +  + ]:          18 :         if (i != 8 && i != 6)
     434                 :             :         {
     435                 :           2 :             errno = PGTYPES_DATE_ERR_ENOSHORTDATE;
     436                 :           2 :             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                 :          16 :         str_copy = pgtypes_alloc(strlen(str) + 1 + 2);
     445         [ -  + ]:          16 :         if (!str_copy)
     446                 :           0 :             return -1;
     447                 :             : 
     448                 :             :         /* determine length of the fragments */
     449         [ +  + ]:          16 :         if (i == 6)
     450                 :             :         {
     451                 :           8 :             frag_length[0] = 2;
     452                 :           8 :             frag_length[1] = 2;
     453                 :           8 :             frag_length[2] = 2;
     454                 :             :         }
     455                 :             :         else
     456                 :             :         {
     457         [ +  + ]:           8 :             if (fmt_token_order[0] == 'y')
     458                 :             :             {
     459                 :           2 :                 frag_length[0] = 4;
     460                 :           2 :                 frag_length[1] = 2;
     461                 :           2 :                 frag_length[2] = 2;
     462                 :             :             }
     463         [ +  + ]:           6 :             else if (fmt_token_order[1] == 'y')
     464                 :             :             {
     465                 :           2 :                 frag_length[0] = 2;
     466                 :           2 :                 frag_length[1] = 4;
     467                 :           2 :                 frag_length[2] = 2;
     468                 :             :             }
     469                 :             :             else
     470                 :             :             {
     471                 :           4 :                 frag_length[0] = 2;
     472                 :           4 :                 frag_length[1] = 2;
     473                 :           4 :                 frag_length[2] = 4;
     474                 :             :             }
     475                 :             :         }
     476                 :          16 :         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                 :             :          */
     483         [ +  + ]:          64 :         for (i = 0; i < 3; i++)
     484                 :             :         {
     485                 :          48 :             int         start_pos = 0;
     486                 :             : 
     487         [ +  + ]:          48 :             if (i >= 1)
     488                 :          32 :                 start_pos += frag_length[0];
     489         [ +  + ]:          48 :             if (i == 2)
     490                 :          16 :                 start_pos += frag_length[1];
     491                 :             : 
     492                 :          48 :             strncpy(str_copy + target_pos, str + start_pos,
     493                 :          48 :                     frag_length[i]);
     494                 :          48 :             target_pos += frag_length[i];
     495         [ +  + ]:          48 :             if (i != 2)
     496                 :             :             {
     497                 :          32 :                 str_copy[target_pos] = ' ';
     498                 :          32 :                 target_pos++;
     499                 :             :             }
     500                 :             :         }
     501                 :          16 :         str_copy[target_pos] = '\0';
     502                 :             :     }
     503                 :             :     else
     504                 :             :     {
     505                 :          46 :         str_copy = pgtypes_strdup(str);
     506         [ -  + ]:          46 :         if (!str_copy)
     507                 :           0 :             return -1;
     508                 :             : 
     509                 :             :         /* convert the whole string to lower case */
     510         [ +  + ]:         888 :         for (i = 0; str_copy[i]; i++)
     511                 :         842 :             str_copy[i] = (char) pg_tolower((unsigned char) str_copy[i]);
     512                 :             :     }
     513                 :             : 
     514                 :             :     /* look for numerical tokens */
     515                 :          62 :     reading_digit = 0;
     516                 :          62 :     token_count = 0;
     517         [ +  + ]:        1048 :     for (i = 0; i < strlen(str_copy); i++)
     518                 :             :     {
     519   [ +  +  +  + ]:         986 :         if (!isdigit((unsigned char) str_copy[i]) && reading_digit)
     520                 :             :         {
     521                 :             :             /* the token is finished */
     522                 :         106 :             token[token_count][1] = i - 1;
     523                 :         106 :             reading_digit = 0;
     524                 :         106 :             token_count++;
     525                 :             :         }
     526   [ +  +  +  + ]:         880 :         else if (isdigit((unsigned char) str_copy[i]) && !reading_digit)
     527                 :             :         {
     528                 :             :             /* we have found a token */
     529                 :         158 :             token[token_count][0] = i;
     530                 :         158 :             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                 :             :      */
     538         [ +  + ]:          62 :     if (reading_digit)
     539                 :             :     {
     540                 :          52 :         token[token_count][1] = i - 1;
     541                 :          52 :         token_count++;
     542                 :             :     }
     543                 :             : 
     544                 :             : 
     545         [ +  + ]:          62 :     if (token_count < 2)
     546                 :             :     {
     547                 :             :         /*
     548                 :             :          * not all tokens found, no way to find 2 missing tokens with string
     549                 :             :          * matches
     550                 :             :          */
     551                 :           2 :         free(str_copy);
     552                 :           2 :         errno = PGTYPES_DATE_ERR_ENOSHORTDATE;
     553                 :           2 :         return -1;
     554                 :             :     }
     555                 :             : 
     556         [ +  + ]:          60 :     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                 :          24 :         char       *month_lower_tmp = pgtypes_alloc(PGTYPES_DATE_MONTH_MAXLENGTH);
     563                 :             :         char       *start_pos;
     564                 :             :         int         j;
     565                 :             :         int         offset;
     566                 :          24 :         int         found = 0;
     567                 :             :         char      **list;
     568                 :             : 
     569         [ -  + ]:          24 :         if (!month_lower_tmp)
     570                 :             :         {
     571                 :             :             /* free variables we alloc'ed before */
     572                 :           0 :             free(str_copy);
     573                 :           0 :             return -1;
     574                 :             :         }
     575                 :          24 :         list = pgtypes_date_months;
     576         [ +  - ]:         368 :         for (i = 0; list[i]; i++)
     577                 :             :         {
     578         [ +  - ]:        2234 :             for (j = 0; j < PGTYPES_DATE_MONTH_MAXLENGTH; j++)
     579                 :             :             {
     580                 :        2234 :                 month_lower_tmp[j] = (char) pg_tolower((unsigned char) list[i][j]);
     581         [ +  + ]:        2234 :                 if (!month_lower_tmp[j])
     582                 :             :                 {
     583                 :             :                     /* properly terminated */
     584                 :         368 :                     break;
     585                 :             :                 }
     586                 :             :             }
     587         [ +  + ]:         368 :             if ((start_pos = strstr(str_copy, month_lower_tmp)))
     588                 :             :             {
     589                 :          24 :                 offset = start_pos - str_copy;
     590                 :             : 
     591                 :             :                 /*
     592                 :             :                  * sort the new token into the numeric tokens, shift them if
     593                 :             :                  * necessary
     594                 :             :                  */
     595         [ +  + ]:          24 :                 if (offset < token[0][0])
     596                 :             :                 {
     597                 :          12 :                     token[2][0] = token[1][0];
     598                 :          12 :                     token[2][1] = token[1][1];
     599                 :          12 :                     token[1][0] = token[0][0];
     600                 :          12 :                     token[1][1] = token[0][1];
     601                 :          12 :                     token_count = 0;
     602                 :             :                 }
     603         [ +  - ]:          12 :                 else if (offset < token[1][0])
     604                 :             :                 {
     605                 :          12 :                     token[2][0] = token[1][0];
     606                 :          12 :                     token[2][1] = token[1][1];
     607                 :          12 :                     token_count = 1;
     608                 :             :                 }
     609                 :             :                 else
     610                 :           0 :                     token_count = 2;
     611                 :          24 :                 token[token_count][0] = offset;
     612                 :          24 :                 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                 :             :                  */
     618                 :          24 :                 token_values[token_count] = i + 1;
     619                 :          24 :                 found = 1;
     620                 :          24 :                 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                 :             :              */
     628         [ +  + ]:         344 :             if (list == pgtypes_date_months)
     629                 :             :             {
     630         [ +  + ]:         236 :                 if (list[i + 1] == NULL)
     631                 :             :                 {
     632                 :          12 :                     list = months;
     633                 :          12 :                     i = -1;
     634                 :             :                 }
     635                 :             :             }
     636                 :             :         }
     637         [ -  + ]:          24 :         if (!found)
     638                 :             :         {
     639                 :           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                 :             :          */
     656         [ -  + ]:          24 :         if (fmt_token_order[token_count] != 'm')
     657                 :             :         {
     658                 :             :             /* deal with the error later on */
     659                 :           0 :             token_values[token_count] = -1;
     660                 :             :         }
     661                 :          24 :         free(month_lower_tmp);
     662                 :             :     }
     663                 :             : 
     664                 :             :     /* terminate the tokens with ASCII-0 and get their values */
     665         [ +  + ]:         240 :     for (i = 0; i < 3; i++)
     666                 :             :     {
     667                 :         180 :         *(str_copy + token[i][1] + 1) = '\0';
     668                 :             :         /* A month already has a value set, check for token_value == -1 */
     669         [ +  + ]:         180 :         if (token_values[i] == -1)
     670                 :             :         {
     671                 :         156 :             errno = 0;
     672                 :         156 :             token_values[i] = strtol(str_copy + token[i][0], (char **) NULL, 10);
     673                 :             :             /* strtol sets errno in case of an error */
     674         [ -  + ]:         156 :             if (errno)
     675                 :           0 :                 token_values[i] = -1;
     676                 :             :         }
     677         [ +  + ]:         180 :         if (fmt_token_order[i] == 'd')
     678                 :          60 :             tm.tm_mday = token_values[i];
     679         [ +  + ]:         120 :         else if (fmt_token_order[i] == 'm')
     680                 :          60 :             tm.tm_mon = token_values[i];
     681         [ +  - ]:          60 :         else if (fmt_token_order[i] == 'y')
     682                 :          60 :             tm.tm_year = token_values[i];
     683                 :             :     }
     684                 :          60 :     free(str_copy);
     685                 :             : 
     686   [ +  -  +  + ]:          60 :     if (tm.tm_mday < 1 || tm.tm_mday > 31)
     687                 :             :     {
     688                 :           2 :         errno = PGTYPES_DATE_BAD_DAY;
     689                 :           2 :         return -1;
     690                 :             :     }
     691                 :             : 
     692   [ +  -  +  + ]:          58 :     if (tm.tm_mon < 1 || tm.tm_mon > MONTHS_PER_YEAR)
     693                 :             :     {
     694                 :           2 :         errno = PGTYPES_DATE_BAD_MONTH;
     695                 :           2 :         return -1;
     696                 :             :     }
     697                 :             : 
     698   [ -  +  -  -  :          56 :     if (tm.tm_mday == 31 && (tm.tm_mon == 4 || tm.tm_mon == 6 || tm.tm_mon == 9 || tm.tm_mon == 11))
          -  -  -  -  -  
                      - ]
     699                 :             :     {
     700                 :           0 :         errno = PGTYPES_DATE_BAD_DAY;
     701                 :           0 :         return -1;
     702                 :             :     }
     703                 :             : 
     704   [ +  +  -  + ]:          56 :     if (tm.tm_mon == 2 && tm.tm_mday > 29)
     705                 :             :     {
     706                 :           0 :         errno = PGTYPES_DATE_BAD_DAY;
     707                 :           0 :         return -1;
     708                 :             :     }
     709                 :             : 
     710                 :          56 :     *d = date2j(tm.tm_year, tm.tm_mon, tm.tm_mday) - date2j(2000, 1, 1);
     711                 :             : 
     712                 :          56 :     return 0;
     713                 :             : }
        

Generated by: LCOV version 2.0-1