LCOV - differential code coverage report
Current view: top level - src/interfaces/ecpg/pgtypeslib - interval.c (source / functions) Coverage Total Hit UBC CBC
Current: Differential Code Coverage 16@8cea358b128 vs 17@8cea358b128 Lines: 33.1 % 602 199 403 199
Current Date: 2024-04-14 14:21:10 Functions: 73.7 % 19 14 5 14
Baseline: 16@8cea358b128 Branches: 16.0 % 413 66 347 66
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: 33.1 % 602 199 403 199
Function coverage date bins:
(240..) days: 73.7 % 19 14 5 14
Branch coverage date bins:
(240..) days: 16.0 % 413 66 347 66

 Age         Owner                    Branch data    TLA  Line data    Source code
                                  1                 :                : /* src/interfaces/ecpg/pgtypeslib/interval.c */
                                  2                 :                : 
                                  3                 :                : #include "postgres_fe.h"
                                  4                 :                : 
                                  5                 :                : #include <time.h>
                                  6                 :                : #include <math.h>
                                  7                 :                : #include <limits.h>
                                  8                 :                : 
                                  9                 :                : #ifdef __FAST_MATH__
                                 10                 :                : #error -ffast-math is known to break this code
                                 11                 :                : #endif
                                 12                 :                : 
                                 13                 :                : #include "common/string.h"
                                 14                 :                : #include "dt.h"
                                 15                 :                : #include "pgtypes_error.h"
                                 16                 :                : #include "pgtypes_interval.h"
                                 17                 :                : #include "pgtypeslib_extern.h"
                                 18                 :                : 
                                 19                 :                : /* copy&pasted from .../src/backend/utils/adt/datetime.c
                                 20                 :                :  * and changed struct pg_tm to struct tm
                                 21                 :                :  */
                                 22                 :                : static void
 2489 tgl@sss.pgh.pa.us          23                 :CBC          38 : AdjustFractSeconds(double frac, struct /* pg_ */ tm *tm, fsec_t *fsec, int scale)
                                 24                 :                : {
                                 25                 :                :     int         sec;
                                 26                 :                : 
 5618 meskes@postgresql.or       27         [ +  - ]:             38 :     if (frac == 0)
                                 28                 :             38 :         return;
 5421 bruce@momjian.us           29                 :UBC           0 :     frac *= scale;
                                 30                 :              0 :     sec = (int) frac;
 5618 meskes@postgresql.or       31                 :              0 :     tm->tm_sec += sec;
 5421 bruce@momjian.us           32                 :              0 :     frac -= sec;
                                 33                 :              0 :     *fsec += rint(frac * 1000000);
                                 34                 :                : }
                                 35                 :                : 
                                 36                 :                : 
                                 37                 :                : /* copy&pasted from .../src/backend/utils/adt/datetime.c
                                 38                 :                :  * and changed struct pg_tm to struct tm
                                 39                 :                :  */
                                 40                 :                : static void
 2489 tgl@sss.pgh.pa.us          41                 :              0 : AdjustFractDays(double frac, struct /* pg_ */ tm *tm, fsec_t *fsec, int scale)
                                 42                 :                : {
                                 43                 :                :     int         extra_days;
                                 44                 :                : 
 5618 meskes@postgresql.or       45         [ #  # ]:              0 :     if (frac == 0)
                                 46                 :              0 :         return;
 5421 bruce@momjian.us           47                 :              0 :     frac *= scale;
                                 48                 :              0 :     extra_days = (int) frac;
 5618 meskes@postgresql.or       49                 :              0 :     tm->tm_mday += extra_days;
 5421 bruce@momjian.us           50                 :              0 :     frac -= extra_days;
 5618 meskes@postgresql.or       51                 :              0 :     AdjustFractSeconds(frac, tm, fsec, SECS_PER_DAY);
                                 52                 :                : }
                                 53                 :                : 
                                 54                 :                : /* copy&pasted from .../src/backend/utils/adt/datetime.c */
                                 55                 :                : static int
 2357 peter_e@gmx.net            56                 :              0 : ParseISO8601Number(const char *str, char **endptr, int *ipart, double *fpart)
                                 57                 :                : {
                                 58                 :                :     double      val;
                                 59                 :                : 
 5618 meskes@postgresql.or       60   [ #  #  #  #  :              0 :     if (!(isdigit((unsigned char) *str) || *str == '-' || *str == '.'))
                                              #  # ]
                                 61                 :              0 :         return DTERR_BAD_FORMAT;
                                 62                 :              0 :     errno = 0;
                                 63                 :              0 :     val = strtod(str, endptr);
                                 64                 :                :     /* did we not see anything that looks like a double? */
                                 65   [ #  #  #  # ]:              0 :     if (*endptr == str || errno != 0)
                                 66                 :              0 :         return DTERR_BAD_FORMAT;
                                 67                 :                :     /* watch out for overflow */
                                 68   [ #  #  #  # ]:              0 :     if (val < INT_MIN || val > INT_MAX)
                                 69                 :              0 :         return DTERR_FIELD_OVERFLOW;
                                 70                 :                :     /* be very sure we truncate towards zero (cf dtrunc()) */
                                 71         [ #  # ]:              0 :     if (val >= 0)
                                 72                 :              0 :         *ipart = (int) floor(val);
                                 73                 :                :     else
                                 74                 :              0 :         *ipart = (int) -floor(-val);
                                 75                 :              0 :     *fpart = val - *ipart;
                                 76                 :              0 :     return 0;
                                 77                 :                : }
                                 78                 :                : 
                                 79                 :                : /* copy&pasted from .../src/backend/utils/adt/datetime.c */
                                 80                 :                : static int
 2357 peter_e@gmx.net            81                 :              0 : ISO8601IntegerWidth(const char *fieldstart)
                                 82                 :                : {
                                 83                 :                :     /* We might have had a leading '-' */
 5618 meskes@postgresql.or       84         [ #  # ]:              0 :     if (*fieldstart == '-')
                                 85                 :              0 :         fieldstart++;
                                 86                 :              0 :     return strspn(fieldstart, "0123456789");
                                 87                 :                : }
                                 88                 :                : 
                                 89                 :                : 
                                 90                 :                : /* copy&pasted from .../src/backend/utils/adt/datetime.c
                                 91                 :                :  * and changed struct pg_tm to struct tm
                                 92                 :                :  */
                                 93                 :                : static inline void
 2489 tgl@sss.pgh.pa.us          94                 :CBC          30 : ClearPgTm(struct /* pg_ */ tm *tm, fsec_t *fsec)
                                 95                 :                : {
 5618 meskes@postgresql.or       96                 :             30 :     tm->tm_year = 0;
 5421 bruce@momjian.us           97                 :             30 :     tm->tm_mon = 0;
 5618 meskes@postgresql.or       98                 :             30 :     tm->tm_mday = 0;
                                 99                 :             30 :     tm->tm_hour = 0;
 5421 bruce@momjian.us          100                 :             30 :     tm->tm_min = 0;
                                101                 :             30 :     tm->tm_sec = 0;
                                102                 :             30 :     *fsec = 0;
 5618 meskes@postgresql.or      103                 :             30 : }
                                104                 :                : 
                                105                 :                : /* copy&pasted from .../src/backend/utils/adt/datetime.c
                                106                 :                :  *
                                107                 :                :  * * changed struct pg_tm to struct tm
                                108                 :                :  *
                                109                 :                :  * * Made the function static
                                110                 :                :  */
                                111                 :                : static int
                                112                 :              1 : DecodeISO8601Interval(char *str,
                                113                 :                :                       int *dtype, struct /* pg_ */ tm *tm, fsec_t *fsec)
                                114                 :                : {
 5421 bruce@momjian.us          115                 :              1 :     bool        datepart = true;
                                116                 :              1 :     bool        havefield = false;
                                117                 :                : 
 5618 meskes@postgresql.or      118                 :              1 :     *dtype = DTK_DELTA;
                                119                 :              1 :     ClearPgTm(tm, fsec);
                                120                 :                : 
                                121   [ +  -  +  - ]:              1 :     if (strlen(str) < 2 || str[0] != 'P')
                                122                 :              1 :         return DTERR_BAD_FORMAT;
                                123                 :                : 
 5618 meskes@postgresql.or      124                 :UBC           0 :     str++;
                                125         [ #  # ]:              0 :     while (*str)
                                126                 :                :     {
                                127                 :                :         char       *fieldstart;
                                128                 :                :         int         val;
                                129                 :                :         double      fval;
                                130                 :                :         char        unit;
                                131                 :                :         int         dterr;
                                132                 :                : 
 5421 bruce@momjian.us          133         [ #  # ]:              0 :         if (*str == 'T')        /* T indicates the beginning of the time part */
                                134                 :                :         {
 5618 meskes@postgresql.or      135                 :              0 :             datepart = false;
                                136                 :              0 :             havefield = false;
                                137                 :              0 :             str++;
                                138                 :              0 :             continue;
                                139                 :                :         }
                                140                 :                : 
                                141                 :              0 :         fieldstart = str;
                                142                 :              0 :         dterr = ParseISO8601Number(str, &str, &val, &fval);
                                143         [ #  # ]:              0 :         if (dterr)
                                144                 :              0 :             return dterr;
                                145                 :                : 
                                146                 :                :         /*
                                147                 :                :          * Note: we could step off the end of the string here.  Code below
                                148                 :                :          * *must* exit the loop if unit == '\0'.
                                149                 :                :          */
                                150                 :              0 :         unit = *str++;
                                151                 :                : 
                                152         [ #  # ]:              0 :         if (datepart)
                                153                 :                :         {
 5421 bruce@momjian.us          154   [ #  #  #  #  :              0 :             switch (unit)       /* before T: Y M W D */
                                           #  #  # ]
                                155                 :                :             {
 5618 meskes@postgresql.or      156                 :              0 :                 case 'Y':
                                157                 :              0 :                     tm->tm_year += val;
  985 bruce@momjian.us          158                 :              0 :                     tm->tm_mon += rint(fval * MONTHS_PER_YEAR);
 5618 meskes@postgresql.or      159                 :              0 :                     break;
                                160                 :              0 :                 case 'M':
                                161                 :              0 :                     tm->tm_mon += val;
                                162                 :              0 :                     AdjustFractDays(fval, tm, fsec, DAYS_PER_MONTH);
                                163                 :              0 :                     break;
                                164                 :              0 :                 case 'W':
                                165                 :              0 :                     tm->tm_mday += val * 7;
                                166                 :              0 :                     AdjustFractDays(fval, tm, fsec, 7);
                                167                 :              0 :                     break;
                                168                 :              0 :                 case 'D':
                                169                 :              0 :                     tm->tm_mday += val;
                                170                 :              0 :                     AdjustFractSeconds(fval, tm, fsec, SECS_PER_DAY);
                                171                 :              0 :                     break;
 5421 bruce@momjian.us          172                 :              0 :                 case 'T':       /* ISO 8601 4.4.3.3 Alternative Format / Basic */
                                173                 :                :                 case '\0':
 5618 meskes@postgresql.or      174   [ #  #  #  # ]:              0 :                     if (ISO8601IntegerWidth(fieldstart) == 8 && !havefield)
                                175                 :                :                     {
                                176                 :              0 :                         tm->tm_year += val / 10000;
 5421 bruce@momjian.us          177                 :              0 :                         tm->tm_mon += (val / 100) % 100;
 5618 meskes@postgresql.or      178                 :              0 :                         tm->tm_mday += val % 100;
                                179                 :              0 :                         AdjustFractSeconds(fval, tm, fsec, SECS_PER_DAY);
                                180         [ #  # ]:              0 :                         if (unit == '\0')
                                181                 :              0 :                             return 0;
                                182                 :              0 :                         datepart = false;
                                183                 :              0 :                         havefield = false;
                                184                 :              0 :                         continue;
                                185                 :                :                     }
                                186                 :                :                     /* Else fall through to extended alternative format */
                                187                 :                :                     /* FALLTHROUGH */
                                188                 :                :                 case '-':       /* ISO 8601 4.4.3.3 Alternative Format,
                                189                 :                :                                  * Extended */
                                190         [ #  # ]:              0 :                     if (havefield)
                                191                 :              0 :                         return DTERR_BAD_FORMAT;
                                192                 :                : 
                                193                 :              0 :                     tm->tm_year += val;
  985 bruce@momjian.us          194                 :              0 :                     tm->tm_mon += rint(fval * MONTHS_PER_YEAR);
 5618 meskes@postgresql.or      195         [ #  # ]:              0 :                     if (unit == '\0')
                                196                 :              0 :                         return 0;
                                197         [ #  # ]:              0 :                     if (unit == 'T')
                                198                 :                :                     {
                                199                 :              0 :                         datepart = false;
                                200                 :              0 :                         havefield = false;
                                201                 :              0 :                         continue;
                                202                 :                :                     }
                                203                 :                : 
                                204                 :              0 :                     dterr = ParseISO8601Number(str, &str, &val, &fval);
                                205         [ #  # ]:              0 :                     if (dterr)
                                206                 :              0 :                         return dterr;
 5421 bruce@momjian.us          207                 :              0 :                     tm->tm_mon += val;
 5618 meskes@postgresql.or      208                 :              0 :                     AdjustFractDays(fval, tm, fsec, DAYS_PER_MONTH);
                                209         [ #  # ]:              0 :                     if (*str == '\0')
                                210                 :              0 :                         return 0;
                                211         [ #  # ]:              0 :                     if (*str == 'T')
                                212                 :                :                     {
                                213                 :              0 :                         datepart = false;
                                214                 :              0 :                         havefield = false;
                                215                 :              0 :                         continue;
                                216                 :                :                     }
                                217         [ #  # ]:              0 :                     if (*str != '-')
                                218                 :              0 :                         return DTERR_BAD_FORMAT;
                                219                 :              0 :                     str++;
                                220                 :                : 
                                221                 :              0 :                     dterr = ParseISO8601Number(str, &str, &val, &fval);
                                222         [ #  # ]:              0 :                     if (dterr)
                                223                 :              0 :                         return dterr;
                                224                 :              0 :                     tm->tm_mday += val;
                                225                 :              0 :                     AdjustFractSeconds(fval, tm, fsec, SECS_PER_DAY);
                                226         [ #  # ]:              0 :                     if (*str == '\0')
                                227                 :              0 :                         return 0;
                                228         [ #  # ]:              0 :                     if (*str == 'T')
                                229                 :                :                     {
                                230                 :              0 :                         datepart = false;
                                231                 :              0 :                         havefield = false;
                                232                 :              0 :                         continue;
                                233                 :                :                     }
                                234                 :              0 :                     return DTERR_BAD_FORMAT;
                                235                 :              0 :                 default:
                                236                 :                :                     /* not a valid date unit suffix */
                                237                 :              0 :                     return DTERR_BAD_FORMAT;
                                238                 :                :             }
                                239                 :                :         }
                                240                 :                :         else
                                241                 :                :         {
 5421 bruce@momjian.us          242   [ #  #  #  #  :              0 :             switch (unit)       /* after T: H M S */
                                              #  # ]
                                243                 :                :             {
 5618 meskes@postgresql.or      244                 :              0 :                 case 'H':
                                245                 :              0 :                     tm->tm_hour += val;
                                246                 :              0 :                     AdjustFractSeconds(fval, tm, fsec, SECS_PER_HOUR);
                                247                 :              0 :                     break;
                                248                 :              0 :                 case 'M':
                                249                 :              0 :                     tm->tm_min += val;
                                250                 :              0 :                     AdjustFractSeconds(fval, tm, fsec, SECS_PER_MINUTE);
                                251                 :              0 :                     break;
                                252                 :              0 :                 case 'S':
                                253                 :              0 :                     tm->tm_sec += val;
                                254                 :              0 :                     AdjustFractSeconds(fval, tm, fsec, 1);
                                255                 :              0 :                     break;
 5421 bruce@momjian.us          256                 :              0 :                 case '\0':      /* ISO 8601 4.4.3.3 Alternative Format */
                                257   [ #  #  #  # ]:              0 :                     if (ISO8601IntegerWidth(fieldstart) == 6 && !havefield)
                                258                 :                :                     {
 5618 meskes@postgresql.or      259                 :              0 :                         tm->tm_hour += val / 10000;
 5421 bruce@momjian.us          260                 :              0 :                         tm->tm_min += (val / 100) % 100;
                                261                 :              0 :                         tm->tm_sec += val % 100;
 5618 meskes@postgresql.or      262                 :              0 :                         AdjustFractSeconds(fval, tm, fsec, 1);
                                263                 :              0 :                         return 0;
                                264                 :                :                     }
                                265                 :                :                     /* Else fall through to extended alternative format */
                                266                 :                :                     /* FALLTHROUGH */
                                267                 :                :                 case ':':       /* ISO 8601 4.4.3.3 Alternative Format,
                                268                 :                :                                  * Extended */
                                269         [ #  # ]:              0 :                     if (havefield)
                                270                 :              0 :                         return DTERR_BAD_FORMAT;
                                271                 :                : 
                                272                 :              0 :                     tm->tm_hour += val;
                                273                 :              0 :                     AdjustFractSeconds(fval, tm, fsec, SECS_PER_HOUR);
                                274         [ #  # ]:              0 :                     if (unit == '\0')
                                275                 :              0 :                         return 0;
                                276                 :                : 
                                277                 :              0 :                     dterr = ParseISO8601Number(str, &str, &val, &fval);
                                278         [ #  # ]:              0 :                     if (dterr)
                                279                 :              0 :                         return dterr;
 5421 bruce@momjian.us          280                 :              0 :                     tm->tm_min += val;
 5618 meskes@postgresql.or      281                 :              0 :                     AdjustFractSeconds(fval, tm, fsec, SECS_PER_MINUTE);
                                282         [ #  # ]:              0 :                     if (*str == '\0')
                                283                 :              0 :                         return 0;
                                284         [ #  # ]:              0 :                     if (*str != ':')
                                285                 :              0 :                         return DTERR_BAD_FORMAT;
                                286                 :              0 :                     str++;
                                287                 :                : 
                                288                 :              0 :                     dterr = ParseISO8601Number(str, &str, &val, &fval);
                                289         [ #  # ]:              0 :                     if (dterr)
                                290                 :              0 :                         return dterr;
 5421 bruce@momjian.us          291                 :              0 :                     tm->tm_sec += val;
 5618 meskes@postgresql.or      292                 :              0 :                     AdjustFractSeconds(fval, tm, fsec, 1);
                                293         [ #  # ]:              0 :                     if (*str == '\0')
                                294                 :              0 :                         return 0;
                                295                 :              0 :                     return DTERR_BAD_FORMAT;
                                296                 :                : 
                                297                 :              0 :                 default:
                                298                 :                :                     /* not a valid time unit suffix */
                                299                 :              0 :                     return DTERR_BAD_FORMAT;
                                300                 :                :             }
                                301                 :                :         }
                                302                 :                : 
                                303                 :              0 :         havefield = true;
                                304                 :                :     }
                                305                 :                : 
                                306                 :              0 :     return 0;
                                307                 :                : }
                                308                 :                : 
                                309                 :                : 
                                310                 :                : 
                                311                 :                : /* copy&pasted from .../src/backend/utils/adt/datetime.c
                                312                 :                :  * with 3 exceptions
                                313                 :                :  *
                                314                 :                :  *  * changed struct pg_tm to struct tm
                                315                 :                :  *
                                316                 :                :  *  * ECPG code called this without a 'range' parameter
                                317                 :                :  *    removed 'int range' from the argument list and
                                318                 :                :  *    places where DecodeTime is called; and added
                                319                 :                :  *       int range = INTERVAL_FULL_RANGE;
                                320                 :                :  *
                                321                 :                :  *  * ECPG seems not to have a global IntervalStyle
                                322                 :                :  *    so added
                                323                 :                :  *      int IntervalStyle = INTSTYLE_POSTGRES;
                                324                 :                :  */
                                325                 :                : int
 2489 tgl@sss.pgh.pa.us         326                 :CBC          29 : DecodeInterval(char **field, int *ftype, int nf,    /* int range, */
                                327                 :                :                int *dtype, struct /* pg_ */ tm *tm, fsec_t *fsec)
                                328                 :                : {
 5421 bruce@momjian.us          329                 :             29 :     int         IntervalStyle = INTSTYLE_POSTGRES_VERBOSE;
                                330                 :             29 :     int         range = INTERVAL_FULL_RANGE;
 2433 peter_e@gmx.net           331                 :             29 :     bool        is_before = false;
                                332                 :                :     char       *cp;
 7686 meskes@postgresql.or      333                 :             29 :     int         fmask = 0,
                                334                 :                :                 tmask,
                                335                 :                :                 type;
                                336                 :                :     int         i;
                                337                 :                :     int         dterr;
                                338                 :                :     int         val;
                                339                 :                :     double      fval;
                                340                 :                : 
                                341                 :             29 :     *dtype = DTK_DELTA;
                                342                 :             29 :     type = IGNORE_DTF;
 5421 bruce@momjian.us          343                 :             29 :     ClearPgTm(tm, fsec);
                                344                 :                : 
                                345                 :                :     /* read through list backwards to pick up units before values */
 7686 meskes@postgresql.or      346         [ +  + ]:            117 :     for (i = nf - 1; i >= 0; i--)
                                347                 :                :     {
                                348   [ +  -  +  +  :             89 :         switch (ftype[i])
                                                 - ]
                                349                 :                :         {
                                350                 :              1 :             case DTK_TIME:
 5421 bruce@momjian.us          351                 :              1 :                 dterr = DecodeTime(field[i],    /* range, */
                                352                 :                :                                    &tmask, tm, fsec);
 5618 meskes@postgresql.or      353         [ -  + ]:              1 :                 if (dterr)
 5618 meskes@postgresql.or      354                 :UBC           0 :                     return dterr;
 7686 meskes@postgresql.or      355                 :CBC           1 :                 type = DTK_DAY;
                                356                 :              1 :                 break;
                                357                 :                : 
 7686 meskes@postgresql.or      358                 :UBC           0 :             case DTK_TZ:
                                359                 :                : 
                                360                 :                :                 /*
                                361                 :                :                  * Timezone is a token with a leading sign character and at
                                362                 :                :                  * least one digit; there could be ':', '.', '-' embedded in
                                363                 :                :                  * it as well.
                                364                 :                :                  */
 2407 peter_e@gmx.net           365   [ #  #  #  # ]:              0 :                 Assert(*field[i] == '-' || *field[i] == '+');
                                366                 :                : 
                                367                 :                :                 /*
                                368                 :                :                  * Try for hh:mm or hh:mm:ss.  If not, fall through to
                                369                 :                :                  * DTK_NUMBER case, which can handle signed float numbers and
                                370                 :                :                  * signed year-month values.
                                371                 :                :                  */
 5618 meskes@postgresql.or      372   [ #  #  #  # ]:              0 :                 if (strchr(field[i] + 1, ':') != NULL &&
 5421 bruce@momjian.us          373                 :              0 :                     DecodeTime(field[i] + 1,    /* INTERVAL_FULL_RANGE, */
                                374                 :                :                                &tmask, tm, fsec) == 0)
                                375                 :                :                 {
 7686 meskes@postgresql.or      376         [ #  # ]:              0 :                     if (*field[i] == '-')
                                377                 :                :                     {
                                378                 :                :                         /* flip the sign on all fields */
                                379                 :              0 :                         tm->tm_hour = -tm->tm_hour;
                                380                 :              0 :                         tm->tm_min = -tm->tm_min;
                                381                 :              0 :                         tm->tm_sec = -tm->tm_sec;
                                382                 :              0 :                         *fsec = -(*fsec);
                                383                 :                :                     }
                                384                 :                : 
                                385                 :                :                     /*
                                386                 :                :                      * Set the next type to be a day, if units are not
                                387                 :                :                      * specified. This handles the case of '1 +02:03' since we
                                388                 :                :                      * are reading right to left.
                                389                 :                :                      */
                                390                 :              0 :                     type = DTK_DAY;
                                391                 :              0 :                     tmask = DTK_M(TZ);
                                392                 :              0 :                     break;
                                393                 :                :                 }
                                394                 :                :                 /* FALL THROUGH */
                                395                 :                : 
                                396                 :                :             case DTK_DATE:
                                397                 :                :             case DTK_NUMBER:
 5618 meskes@postgresql.or      398         [ -  + ]:CBC          44 :                 if (type == IGNORE_DTF)
                                399                 :                :                 {
                                400                 :                :                     /* use typmod to decide what rightmost field is */
                                401                 :                :                     switch (range)
                                402                 :                :                     {
 5618 meskes@postgresql.or      403                 :UBC           0 :                         case INTERVAL_MASK(YEAR):
                                404                 :              0 :                             type = DTK_YEAR;
                                405                 :              0 :                             break;
                                406                 :              0 :                         case INTERVAL_MASK(MONTH):
                                407                 :                :                         case INTERVAL_MASK(YEAR) | INTERVAL_MASK(MONTH):
                                408                 :              0 :                             type = DTK_MONTH;
                                409                 :              0 :                             break;
                                410                 :              0 :                         case INTERVAL_MASK(DAY):
                                411                 :              0 :                             type = DTK_DAY;
                                412                 :              0 :                             break;
                                413                 :              0 :                         case INTERVAL_MASK(HOUR):
                                414                 :                :                         case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR):
                                415                 :                :                         case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE):
                                416                 :                :                         case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND):
                                417                 :              0 :                             type = DTK_HOUR;
                                418                 :              0 :                             break;
                                419                 :              0 :                         case INTERVAL_MASK(MINUTE):
                                420                 :                :                         case INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE):
                                421                 :              0 :                             type = DTK_MINUTE;
                                422                 :              0 :                             break;
                                423                 :              0 :                         case INTERVAL_MASK(SECOND):
                                424                 :                :                         case INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND):
                                425                 :                :                         case INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND):
                                426                 :              0 :                             type = DTK_SECOND;
                                427                 :              0 :                             break;
                                428                 :              0 :                         default:
                                429                 :              0 :                             type = DTK_SECOND;
                                430                 :              0 :                             break;
                                431                 :                :                     }
                                432                 :                :                 }
                                433                 :                : 
 5618 meskes@postgresql.or      434                 :CBC          44 :                 errno = 0;
 2913 tgl@sss.pgh.pa.us         435                 :             44 :                 val = strtoint(field[i], &cp, 10);
 5618 meskes@postgresql.or      436         [ -  + ]:             44 :                 if (errno == ERANGE)
 5618 meskes@postgresql.or      437                 :UBC           0 :                     return DTERR_FIELD_OVERFLOW;
                                438                 :                : 
 5618 meskes@postgresql.or      439         [ -  + ]:CBC          44 :                 if (*cp == '-')
                                440                 :                :                 {
                                441                 :                :                     /* SQL "years-months" syntax */
                                442                 :                :                     int         val2;
                                443                 :                : 
 2913 tgl@sss.pgh.pa.us         444                 :UBC           0 :                     val2 = strtoint(cp + 1, &cp, 10);
 5618 meskes@postgresql.or      445   [ #  #  #  #  :              0 :                     if (errno == ERANGE || val2 < 0 || val2 >= MONTHS_PER_YEAR)
                                              #  # ]
                                446                 :              0 :                         return DTERR_FIELD_OVERFLOW;
                                447         [ #  # ]:              0 :                     if (*cp != '\0')
                                448                 :              0 :                         return DTERR_BAD_FORMAT;
                                449                 :              0 :                     type = DTK_MONTH;
                                450         [ #  # ]:              0 :                     if (*field[i] == '-')
                                451                 :              0 :                         val2 = -val2;
                                452                 :              0 :                     val = val * MONTHS_PER_YEAR + val2;
                                453                 :              0 :                     fval = 0;
                                454                 :                :                 }
 5618 meskes@postgresql.or      455         [ -  + ]:CBC          44 :                 else if (*cp == '.')
                                456                 :                :                 {
 5618 meskes@postgresql.or      457                 :UBC           0 :                     errno = 0;
 7686                           458                 :              0 :                     fval = strtod(cp, &cp);
 5618                           459   [ #  #  #  # ]:              0 :                     if (*cp != '\0' || errno != 0)
                                460                 :              0 :                         return DTERR_BAD_FORMAT;
                                461                 :                : 
                                462         [ #  # ]:              0 :                     if (*field[i] == '-')
 6900 bruce@momjian.us          463                 :              0 :                         fval = -fval;
                                464                 :                :                 }
 7686 meskes@postgresql.or      465         [ +  - ]:CBC          44 :                 else if (*cp == '\0')
                                466                 :             44 :                     fval = 0;
                                467                 :                :                 else
 5618 meskes@postgresql.or      468                 :UBC           0 :                     return DTERR_BAD_FORMAT;
                                469                 :                : 
 7686 meskes@postgresql.or      470   [ -  -  +  +  :CBC          44 :                 tmask = 0;      /* DTK_M(type); */
                                     +  +  -  -  +  
                                        -  -  -  - ]
                                471                 :                : 
                                472                 :                :                 switch (type)
                                473                 :                :                 {
 7686 meskes@postgresql.or      474                 :UBC           0 :                     case DTK_MICROSEC:
 5618                           475                 :              0 :                         *fsec += rint(val + fval);
                                476                 :              0 :                         tmask = DTK_M(MICROSECOND);
 7686                           477                 :              0 :                         break;
                                478                 :                : 
                                479                 :              0 :                     case DTK_MILLISEC:
 5618                           480                 :              0 :                         *fsec += rint((val + fval) * 1000);
                                481                 :              0 :                         tmask = DTK_M(MILLISECOND);
 7686                           482                 :              0 :                         break;
                                483                 :                : 
 7686 meskes@postgresql.or      484                 :CBC           5 :                     case DTK_SECOND:
                                485                 :              5 :                         tm->tm_sec += val;
 5618                           486                 :              5 :                         *fsec += rint(fval * 1000000);
                                487                 :                : 
                                488                 :                :                         /*
                                489                 :                :                          * If any subseconds were specified, consider this
                                490                 :                :                          * microsecond and millisecond input as well.
                                491                 :                :                          */
                                492         [ +  - ]:              5 :                         if (fval == 0)
                                493                 :              5 :                             tmask = DTK_M(SECOND);
                                494                 :                :                         else
 5618 meskes@postgresql.or      495                 :UBC           0 :                             tmask = DTK_ALL_SECS_M;
 7686 meskes@postgresql.or      496                 :CBC           5 :                         break;
                                497                 :                : 
                                498                 :              7 :                     case DTK_MINUTE:
                                499                 :              7 :                         tm->tm_min += val;
 5618                           500                 :              7 :                         AdjustFractSeconds(fval, tm, fsec, SECS_PER_MINUTE);
 7686                           501                 :              7 :                         tmask = DTK_M(MINUTE);
                                502                 :              7 :                         break;
                                503                 :                : 
                                504                 :             25 :                     case DTK_HOUR:
                                505                 :             25 :                         tm->tm_hour += val;
 5618                           506                 :             25 :                         AdjustFractSeconds(fval, tm, fsec, SECS_PER_HOUR);
 7686                           507                 :             25 :                         tmask = DTK_M(HOUR);
 5618                           508                 :             25 :                         type = DTK_DAY;
 7686                           509                 :             25 :                         break;
                                510                 :                : 
                                511                 :              6 :                     case DTK_DAY:
                                512                 :              6 :                         tm->tm_mday += val;
 5618                           513                 :              6 :                         AdjustFractSeconds(fval, tm, fsec, SECS_PER_DAY);
 6900 bruce@momjian.us          514         [ -  + ]:              6 :                         tmask = (fmask & DTK_M(DAY)) ? 0 : DTK_M(DAY);
 7686 meskes@postgresql.or      515                 :              6 :                         break;
                                516                 :                : 
 7686 meskes@postgresql.or      517                 :UBC           0 :                     case DTK_WEEK:
                                518                 :              0 :                         tm->tm_mday += val * 7;
 5618                           519                 :              0 :                         AdjustFractDays(fval, tm, fsec, 7);
 6900 bruce@momjian.us          520         [ #  # ]:              0 :                         tmask = (fmask & DTK_M(DAY)) ? 0 : DTK_M(DAY);
 7686 meskes@postgresql.or      521                 :              0 :                         break;
                                522                 :                : 
                                523                 :              0 :                     case DTK_MONTH:
                                524                 :              0 :                         tm->tm_mon += val;
 5618                           525                 :              0 :                         AdjustFractDays(fval, tm, fsec, DAYS_PER_MONTH);
 7686                           526                 :              0 :                         tmask = DTK_M(MONTH);
                                527                 :              0 :                         break;
                                528                 :                : 
 7686 meskes@postgresql.or      529                 :CBC           1 :                     case DTK_YEAR:
                                530                 :              1 :                         tm->tm_year += val;
  985 bruce@momjian.us          531                 :              1 :                         tm->tm_mon += rint(fval * MONTHS_PER_YEAR);
 6900                           532         [ -  + ]:              1 :                         tmask = (fmask & DTK_M(YEAR)) ? 0 : DTK_M(YEAR);
 7686 meskes@postgresql.or      533                 :              1 :                         break;
                                534                 :                : 
 7686 meskes@postgresql.or      535                 :UBC           0 :                     case DTK_DECADE:
                                536                 :              0 :                         tm->tm_year += val * 10;
  985 bruce@momjian.us          537                 :              0 :                         tm->tm_mon += rint(fval * MONTHS_PER_YEAR * 10);
 6900                           538         [ #  # ]:              0 :                         tmask = (fmask & DTK_M(YEAR)) ? 0 : DTK_M(YEAR);
 7686 meskes@postgresql.or      539                 :              0 :                         break;
                                540                 :                : 
                                541                 :              0 :                     case DTK_CENTURY:
                                542                 :              0 :                         tm->tm_year += val * 100;
  985 bruce@momjian.us          543                 :              0 :                         tm->tm_mon += rint(fval * MONTHS_PER_YEAR * 100);
 6900                           544         [ #  # ]:              0 :                         tmask = (fmask & DTK_M(YEAR)) ? 0 : DTK_M(YEAR);
 7686 meskes@postgresql.or      545                 :              0 :                         break;
                                546                 :                : 
                                547                 :              0 :                     case DTK_MILLENNIUM:
                                548                 :              0 :                         tm->tm_year += val * 1000;
  985 bruce@momjian.us          549                 :              0 :                         tm->tm_mon += rint(fval * MONTHS_PER_YEAR * 1000);
 6900                           550         [ #  # ]:              0 :                         tmask = (fmask & DTK_M(YEAR)) ? 0 : DTK_M(YEAR);
 7686 meskes@postgresql.or      551                 :              0 :                         break;
                                552                 :                : 
                                553                 :              0 :                     default:
 5618                           554                 :              0 :                         return DTERR_BAD_FORMAT;
                                555                 :                :                 }
 7686 meskes@postgresql.or      556                 :CBC          44 :                 break;
                                557                 :                : 
                                558                 :             44 :             case DTK_STRING:
                                559                 :                :             case DTK_SPECIAL:
                                560                 :             44 :                 type = DecodeUnits(i, field[i], &val);
                                561         [ -  + ]:             44 :                 if (type == IGNORE_DTF)
 7686 meskes@postgresql.or      562                 :UBC           0 :                     continue;
                                563                 :                : 
 7686 meskes@postgresql.or      564   [ +  -  -  + ]:CBC          44 :                 tmask = 0;      /* DTK_M(type); */
                                565                 :                :                 switch (type)
                                566                 :                :                 {
                                567                 :             43 :                     case UNITS:
                                568                 :             43 :                         type = val;
                                569                 :             43 :                         break;
                                570                 :                : 
 7686 meskes@postgresql.or      571                 :UBC           0 :                     case AGO:
 2433 peter_e@gmx.net           572                 :              0 :                         is_before = true;
 7686 meskes@postgresql.or      573                 :              0 :                         type = val;
                                574                 :              0 :                         break;
                                575                 :                : 
                                576                 :              0 :                     case RESERV:
 5004 tgl@sss.pgh.pa.us         577                 :              0 :                         tmask = (DTK_DATE_M | DTK_TIME_M);
 7686 meskes@postgresql.or      578                 :              0 :                         *dtype = val;
                                579                 :              0 :                         break;
                                580                 :                : 
 7686 meskes@postgresql.or      581                 :CBC           1 :                     default:
 5618                           582                 :              1 :                         return DTERR_BAD_FORMAT;
                                583                 :                :                 }
 7686                           584                 :             43 :                 break;
                                585                 :                : 
 7686 meskes@postgresql.or      586                 :UBC           0 :             default:
 5618                           587                 :              0 :                 return DTERR_BAD_FORMAT;
                                588                 :                :         }
                                589                 :                : 
 7686 meskes@postgresql.or      590         [ -  + ]:CBC          88 :         if (tmask & fmask)
 5618 meskes@postgresql.or      591                 :UBC           0 :             return DTERR_BAD_FORMAT;
 7686 meskes@postgresql.or      592                 :CBC          88 :         fmask |= tmask;
                                593                 :                :     }
                                594                 :                : 
                                595                 :                :     /* ensure that at least one time field has been found */
 5618                           596         [ -  + ]:             28 :     if (fmask == 0)
 5618 meskes@postgresql.or      597                 :UBC           0 :         return DTERR_BAD_FORMAT;
                                598                 :                : 
                                599                 :                :     /* ensure fractional seconds are fractional */
 7686 meskes@postgresql.or      600         [ -  + ]:CBC          28 :     if (*fsec != 0)
                                601                 :                :     {
                                602                 :                :         int         sec;
                                603                 :                : 
 6764 bruce@momjian.us          604                 :UBC           0 :         sec = *fsec / USECS_PER_SEC;
                                605                 :              0 :         *fsec -= sec * USECS_PER_SEC;
 7686 meskes@postgresql.or      606                 :              0 :         tm->tm_sec += sec;
                                607                 :                :     }
                                608                 :                : 
                                609                 :                :     /*----------
                                610                 :                :      * The SQL standard defines the interval literal
                                611                 :                :      *   '-1 1:00:00'
                                612                 :                :      * to mean "negative 1 days and negative 1 hours", while Postgres
                                613                 :                :      * traditionally treats this as meaning "negative 1 days and positive
                                614                 :                :      * 1 hours".  In SQL_STANDARD intervalstyle, we apply the leading sign
                                615                 :                :      * to all fields if there are no other explicit signs.
                                616                 :                :      *
                                617                 :                :      * We leave the signs alone if there are additional explicit signs.
                                618                 :                :      * This protects us against misinterpreting postgres-style dump output,
                                619                 :                :      * since the postgres-style output code has always put an explicit sign on
                                620                 :                :      * all fields following a negative field.  But note that SQL-spec output
                                621                 :                :      * is ambiguous and can be misinterpreted on load!  (So it's best practice
                                622                 :                :      * to dump in postgres style, not SQL style.)
                                623                 :                :      *----------
                                624                 :                :      */
 5618 meskes@postgresql.or      625   [ -  +  -  - ]:CBC          28 :     if (IntervalStyle == INTSTYLE_SQL_STANDARD && *field[0] == '-')
                                626                 :                :     {
                                627                 :                :         /* Check for additional explicit signs */
 5421 bruce@momjian.us          628                 :UBC           0 :         bool        more_signs = false;
                                629                 :                : 
 5618 meskes@postgresql.or      630         [ #  # ]:              0 :         for (i = 1; i < nf; i++)
                                631                 :                :         {
                                632   [ #  #  #  # ]:              0 :             if (*field[i] == '-' || *field[i] == '+')
                                633                 :                :             {
                                634                 :              0 :                 more_signs = true;
                                635                 :              0 :                 break;
                                636                 :                :             }
                                637                 :                :         }
                                638                 :                : 
                                639         [ #  # ]:              0 :         if (!more_signs)
                                640                 :                :         {
                                641                 :                :             /*
                                642                 :                :              * Rather than re-determining which field was field[0], just force
                                643                 :                :              * 'em all negative.
                                644                 :                :              */
                                645         [ #  # ]:              0 :             if (*fsec > 0)
                                646                 :              0 :                 *fsec = -(*fsec);
                                647         [ #  # ]:              0 :             if (tm->tm_sec > 0)
                                648                 :              0 :                 tm->tm_sec = -tm->tm_sec;
                                649         [ #  # ]:              0 :             if (tm->tm_min > 0)
                                650                 :              0 :                 tm->tm_min = -tm->tm_min;
                                651         [ #  # ]:              0 :             if (tm->tm_hour > 0)
                                652                 :              0 :                 tm->tm_hour = -tm->tm_hour;
                                653         [ #  # ]:              0 :             if (tm->tm_mday > 0)
                                654                 :              0 :                 tm->tm_mday = -tm->tm_mday;
                                655         [ #  # ]:              0 :             if (tm->tm_mon > 0)
                                656                 :              0 :                 tm->tm_mon = -tm->tm_mon;
                                657         [ #  # ]:              0 :             if (tm->tm_year > 0)
                                658                 :              0 :                 tm->tm_year = -tm->tm_year;
                                659                 :                :         }
                                660                 :                :     }
                                661                 :                : 
                                662                 :                :     /* finally, AGO negates everything */
 7686 meskes@postgresql.or      663         [ -  + ]:CBC          28 :     if (is_before)
                                664                 :                :     {
 7686 meskes@postgresql.or      665                 :UBC           0 :         *fsec = -(*fsec);
 5618                           666                 :              0 :         tm->tm_sec = -tm->tm_sec;
                                667                 :              0 :         tm->tm_min = -tm->tm_min;
                                668                 :              0 :         tm->tm_hour = -tm->tm_hour;
                                669                 :              0 :         tm->tm_mday = -tm->tm_mday;
                                670                 :              0 :         tm->tm_mon = -tm->tm_mon;
                                671                 :              0 :         tm->tm_year = -tm->tm_year;
                                672                 :                :     }
                                673                 :                : 
 5618 meskes@postgresql.or      674                 :CBC          28 :     return 0;
                                675                 :                : }
                                676                 :                : 
                                677                 :                : 
                                678                 :                : /* copy&pasted from .../src/backend/utils/adt/datetime.c */
                                679                 :                : static char *
                                680                 :            270 : AddVerboseIntPart(char *cp, int value, const char *units,
                                681                 :                :                   bool *is_zero, bool *is_before)
                                682                 :                : {
                                683         [ +  + ]:            270 :     if (value == 0)
                                684                 :            195 :         return cp;
                                685                 :                :     /* first nonzero value sets is_before */
                                686         [ +  + ]:             75 :     if (*is_zero)
                                687                 :                :     {
                                688                 :             54 :         *is_before = (value < 0);
                                689                 :             54 :         value = abs(value);
                                690                 :                :     }
                                691         [ -  + ]:             21 :     else if (*is_before)
 5618 meskes@postgresql.or      692                 :UBC           0 :         value = -value;
 1079 bruce@momjian.us          693         [ +  + ]:CBC          75 :     sprintf(cp, " %d %s%s", value, units, (value == 1) ? "" : "s");
 2433 peter_e@gmx.net           694                 :             75 :     *is_zero = false;
 5618 meskes@postgresql.or      695                 :             75 :     return cp + strlen(cp);
                                696                 :                : }
                                697                 :                : 
                                698                 :                : /* copy&pasted from .../src/backend/utils/adt/datetime.c */
                                699                 :                : static char *
 5618 meskes@postgresql.or      700                 :UBC           0 : AddPostgresIntPart(char *cp, int value, const char *units,
                                701                 :                :                    bool *is_zero, bool *is_before)
                                702                 :                : {
                                703         [ #  # ]:              0 :     if (value == 0)
                                704                 :              0 :         return cp;
                                705         [ #  # ]:              0 :     sprintf(cp, "%s%s%d %s%s",
                                706         [ #  # ]:              0 :             (!*is_zero) ? " " : "",
                                707   [ #  #  #  # ]:              0 :             (*is_before && value > 0) ? "+" : "",
                                708                 :                :             value,
                                709                 :                :             units,
                                710                 :                :             (value != 1) ? "s" : "");
                                711                 :                : 
                                712                 :                :     /*
                                713                 :                :      * Each nonzero field sets is_before for (only) the next one.  This is a
                                714                 :                :      * tad bizarre but it's how it worked before...
                                715                 :                :      */
                                716                 :              0 :     *is_before = (value < 0);
 2433 peter_e@gmx.net           717                 :              0 :     *is_zero = false;
 5618 meskes@postgresql.or      718                 :              0 :     return cp + strlen(cp);
                                719                 :                : }
                                720                 :                : 
                                721                 :                : /* copy&pasted from .../src/backend/utils/adt/datetime.c */
                                722                 :                : static char *
                                723                 :              0 : AddISO8601IntPart(char *cp, int value, char units)
                                724                 :                : {
                                725         [ #  # ]:              0 :     if (value == 0)
                                726                 :              0 :         return cp;
                                727                 :              0 :     sprintf(cp, "%d%c", value, units);
                                728                 :              0 :     return cp + strlen(cp);
                                729                 :                : }
                                730                 :                : 
                                731                 :                : /* copy&pasted from .../src/backend/utils/adt/datetime.c */
                                732                 :                : static void
 5618 meskes@postgresql.or      733                 :CBC          10 : AppendSeconds(char *cp, int sec, fsec_t fsec, int precision, bool fillzeros)
                                734                 :                : {
                                735         [ +  - ]:             10 :     if (fsec == 0)
                                736                 :                :     {
                                737         [ -  + ]:             10 :         if (fillzeros)
 5618 meskes@postgresql.or      738                 :UBC           0 :             sprintf(cp, "%02d", abs(sec));
                                739                 :                :         else
 5618 meskes@postgresql.or      740                 :CBC          10 :             sprintf(cp, "%d", abs(sec));
                                741                 :                :     }
                                742                 :                :     else
                                743                 :                :     {
 5618 meskes@postgresql.or      744         [ #  # ]:UBC           0 :         if (fillzeros)
  555 peter@eisentraut.org      745                 :              0 :             sprintf(cp, "%02d.%0*d", abs(sec), precision, abs(fsec));
                                746                 :                :         else
                                747                 :              0 :             sprintf(cp, "%d.%0*d", abs(sec), precision, abs(fsec));
 5618 meskes@postgresql.or      748                 :              0 :         TrimTrailingZeros(cp);
                                749                 :                :     }
 5618 meskes@postgresql.or      750                 :CBC          10 : }
                                751                 :                : 
                                752                 :                : 
                                753                 :                : /* copy&pasted from .../src/backend/utils/adt/datetime.c
                                754                 :                :  *
                                755                 :                :  * Change pg_tm to tm
                                756                 :                :  */
                                757                 :                : 
                                758                 :                : void
 2489 tgl@sss.pgh.pa.us         759                 :             54 : EncodeInterval(struct /* pg_ */ tm *tm, fsec_t fsec, int style, char *str)
                                760                 :                : {
 7686 meskes@postgresql.or      761                 :             54 :     char       *cp = str;
 5618                           762                 :             54 :     int         year = tm->tm_year;
 5421 bruce@momjian.us          763                 :             54 :     int         mon = tm->tm_mon;
 5618 meskes@postgresql.or      764                 :             54 :     int         mday = tm->tm_mday;
                                765                 :             54 :     int         hour = tm->tm_hour;
 5421 bruce@momjian.us          766                 :             54 :     int         min = tm->tm_min;
                                767                 :             54 :     int         sec = tm->tm_sec;
 2433 peter_e@gmx.net           768                 :             54 :     bool        is_before = false;
                                769                 :             54 :     bool        is_zero = true;
                                770                 :                : 
                                771                 :                :     /*
                                772                 :                :      * The sign of year and month are guaranteed to match, since they are
                                773                 :                :      * stored internally as "month". But we'll need to check for is_before and
                                774                 :                :      * is_zero when determining the signs of day and hour/minute/seconds
                                775                 :                :      * fields.
                                776                 :                :      */
 7686 meskes@postgresql.or      777   [ -  -  -  + ]:             54 :     switch (style)
                                778                 :                :     {
                                779                 :                :             /* SQL Standard interval format */
 5618 meskes@postgresql.or      780                 :UBC           0 :         case INTSTYLE_SQL_STANDARD:
                                781                 :                :             {
 5421 bruce@momjian.us          782   [ #  #  #  # ]:              0 :                 bool        has_negative = year < 0 || mon < 0 ||
  331 tgl@sss.pgh.pa.us         783   [ #  #  #  # ]:              0 :                     mday < 0 || hour < 0 ||
                                784   [ #  #  #  #  :              0 :                     min < 0 || sec < 0 || fsec < 0;
                                              #  # ]
 5421 bruce@momjian.us          785   [ #  #  #  # ]:              0 :                 bool        has_positive = year > 0 || mon > 0 ||
  331 tgl@sss.pgh.pa.us         786   [ #  #  #  # ]:              0 :                     mday > 0 || hour > 0 ||
                                787   [ #  #  #  #  :              0 :                     min > 0 || sec > 0 || fsec > 0;
                                              #  # ]
 5421 bruce@momjian.us          788   [ #  #  #  # ]:              0 :                 bool        has_year_month = year != 0 || mon != 0;
                                789   [ #  #  #  # ]:              0 :                 bool        has_day_time = mday != 0 || hour != 0 ||
  331 tgl@sss.pgh.pa.us         790   [ #  #  #  #  :              0 :                     min != 0 || sec != 0 || fsec != 0;
                                              #  # ]
 5421 bruce@momjian.us          791                 :              0 :                 bool        has_day = mday != 0;
                                792   [ #  #  #  # ]:              0 :                 bool        sql_standard_value = !(has_negative && has_positive) &&
  331 tgl@sss.pgh.pa.us         793   [ #  #  #  # ]:              0 :                     !(has_year_month && has_day_time);
                                794                 :                : 
                                795                 :                :                 /*
                                796                 :                :                  * SQL Standard wants only 1 "<sign>" preceding the whole
                                797                 :                :                  * interval ... but can't do that if mixed signs.
                                798                 :                :                  */
 5618 meskes@postgresql.or      799   [ #  #  #  # ]:              0 :                 if (has_negative && sql_standard_value)
                                800                 :                :                 {
                                801                 :              0 :                     *cp++ = '-';
                                802                 :              0 :                     year = -year;
 5421 bruce@momjian.us          803                 :              0 :                     mon = -mon;
 5618 meskes@postgresql.or      804                 :              0 :                     mday = -mday;
                                805                 :              0 :                     hour = -hour;
 5421 bruce@momjian.us          806                 :              0 :                     min = -min;
                                807                 :              0 :                     sec = -sec;
 5618 meskes@postgresql.or      808                 :              0 :                     fsec = -fsec;
                                809                 :                :                 }
                                810                 :                : 
                                811   [ #  #  #  # ]:              0 :                 if (!has_negative && !has_positive)
                                812                 :                :                 {
                                813                 :              0 :                     sprintf(cp, "0");
                                814                 :                :                 }
                                815         [ #  # ]:              0 :                 else if (!sql_standard_value)
                                816                 :                :                 {
                                817                 :                :                     /*
                                818                 :                :                      * For non sql-standard interval values, force outputting
                                819                 :                :                      * the signs to avoid ambiguities with intervals with
                                820                 :                :                      * mixed sign components.
                                821                 :                :                      */
 5421 bruce@momjian.us          822   [ #  #  #  # ]:              0 :                     char        year_sign = (year < 0 || mon < 0) ? '-' : '+';
                                823         [ #  # ]:              0 :                     char        day_sign = (mday < 0) ? '-' : '+';
                                824   [ #  #  #  #  :              0 :                     char        sec_sign = (hour < 0 || min < 0 ||
                                              #  # ]
                                825         [ #  # ]:              0 :                                             sec < 0 || fsec < 0) ? '-' : '+';
                                826                 :                : 
 5618 meskes@postgresql.or      827                 :              0 :                     sprintf(cp, "%c%d-%d %c%d %c%d:%02d:",
                                828                 :                :                             year_sign, abs(year), abs(mon),
                                829                 :                :                             day_sign, abs(mday),
                                830                 :                :                             sec_sign, abs(hour), abs(min));
 7686                           831                 :              0 :                     cp += strlen(cp);
 5618                           832                 :              0 :                     AppendSeconds(cp, sec, fsec, MAX_INTERVAL_PRECISION, true);
                                833                 :                :                 }
                                834         [ #  # ]:              0 :                 else if (has_year_month)
                                835                 :                :                 {
                                836                 :              0 :                     sprintf(cp, "%d-%d", year, mon);
                                837                 :                :                 }
                                838         [ #  # ]:              0 :                 else if (has_day)
                                839                 :                :                 {
                                840                 :              0 :                     sprintf(cp, "%d %d:%02d:", mday, hour, min);
 7686                           841                 :              0 :                     cp += strlen(cp);
 5618                           842                 :              0 :                     AppendSeconds(cp, sec, fsec, MAX_INTERVAL_PRECISION, true);
                                843                 :                :                 }
                                844                 :                :                 else
                                845                 :                :                 {
                                846                 :              0 :                     sprintf(cp, "%d:%02d:", hour, min);
 7686                           847                 :              0 :                     cp += strlen(cp);
 5618                           848                 :              0 :                     AppendSeconds(cp, sec, fsec, MAX_INTERVAL_PRECISION, true);
                                849                 :                :                 }
                                850                 :                :             }
 7686                           851                 :              0 :             break;
                                852                 :                : 
                                853                 :                :             /* ISO 8601 "time-intervals by duration only" */
 5618                           854                 :              0 :         case INTSTYLE_ISO_8601:
                                855                 :                :             /* special-case zero to avoid printing nothing */
                                856   [ #  #  #  #  :              0 :             if (year == 0 && mon == 0 && mday == 0 &&
                                        #  #  #  # ]
 5421 bruce@momjian.us          857   [ #  #  #  #  :              0 :                 hour == 0 && min == 0 && sec == 0 && fsec == 0)
                                              #  # ]
                                858                 :                :             {
 5618 meskes@postgresql.or      859                 :              0 :                 sprintf(cp, "PT0S");
                                860                 :              0 :                 break;
                                861                 :                :             }
                                862                 :              0 :             *cp++ = 'P';
                                863                 :              0 :             cp = AddISO8601IntPart(cp, year, 'Y');
 5421 bruce@momjian.us          864                 :              0 :             cp = AddISO8601IntPart(cp, mon, 'M');
 5618 meskes@postgresql.or      865                 :              0 :             cp = AddISO8601IntPart(cp, mday, 'D');
                                866   [ #  #  #  #  :              0 :             if (hour != 0 || min != 0 || sec != 0 || fsec != 0)
                                        #  #  #  # ]
                                867                 :              0 :                 *cp++ = 'T';
                                868                 :              0 :             cp = AddISO8601IntPart(cp, hour, 'H');
 5421 bruce@momjian.us          869                 :              0 :             cp = AddISO8601IntPart(cp, min, 'M');
 5618 meskes@postgresql.or      870   [ #  #  #  # ]:              0 :             if (sec != 0 || fsec != 0)
                                871                 :                :             {
                                872   [ #  #  #  # ]:              0 :                 if (sec < 0 || fsec < 0)
                                873                 :              0 :                     *cp++ = '-';
                                874                 :              0 :                 AppendSeconds(cp, sec, fsec, MAX_INTERVAL_PRECISION, false);
 7686                           875                 :              0 :                 cp += strlen(cp);
 5618                           876                 :              0 :                 *cp++ = 'S';
 5337                           877                 :              0 :                 *cp = '\0';
                                878                 :                :             }
 5618                           879                 :              0 :             break;
                                880                 :                : 
                                881                 :                :             /* Compatible with postgresql < 8.4 when DateStyle = 'iso' */
                                882                 :              0 :         case INTSTYLE_POSTGRES:
                                883                 :              0 :             cp = AddPostgresIntPart(cp, year, "year", &is_zero, &is_before);
                                884                 :              0 :             cp = AddPostgresIntPart(cp, mon, "mon", &is_zero, &is_before);
                                885                 :              0 :             cp = AddPostgresIntPart(cp, mday, "day", &is_zero, &is_before);
                                886   [ #  #  #  #  :              0 :             if (is_zero || hour != 0 || min != 0 || sec != 0 || fsec != 0)
                                     #  #  #  #  #  
                                                 # ]
                                887                 :                :             {
 5421 bruce@momjian.us          888   [ #  #  #  #  :              0 :                 bool        minus = (hour < 0 || min < 0 || sec < 0 || fsec < 0);
                                        #  #  #  # ]
                                889                 :                : 
 5618 meskes@postgresql.or      890         [ #  # ]:              0 :                 sprintf(cp, "%s%s%02d:%02d:",
                                891         [ #  # ]:              0 :                         is_zero ? "" : " ",
                                892         [ #  # ]:              0 :                         (minus ? "-" : (is_before ? "+" : "")),
                                893                 :                :                         abs(hour), abs(min));
 7686                           894                 :              0 :                 cp += strlen(cp);
 5618                           895                 :              0 :                 AppendSeconds(cp, sec, fsec, MAX_INTERVAL_PRECISION, true);
                                896                 :                :             }
                                897                 :              0 :             break;
                                898                 :                : 
                                899                 :                :             /* Compatible with postgresql < 8.4 when DateStyle != 'iso' */
 5618 meskes@postgresql.or      900                 :CBC          54 :         case INTSTYLE_POSTGRES_VERBOSE:
                                901                 :                :         default:
                                902                 :             54 :             strcpy(cp, "@");
                                903                 :             54 :             cp++;
                                904                 :             54 :             cp = AddVerboseIntPart(cp, year, "year", &is_zero, &is_before);
                                905                 :             54 :             cp = AddVerboseIntPart(cp, mon, "mon", &is_zero, &is_before);
                                906                 :             54 :             cp = AddVerboseIntPart(cp, mday, "day", &is_zero, &is_before);
                                907                 :             54 :             cp = AddVerboseIntPart(cp, hour, "hour", &is_zero, &is_before);
                                908                 :             54 :             cp = AddVerboseIntPart(cp, min, "min", &is_zero, &is_before);
                                909   [ +  +  -  + ]:             54 :             if (sec != 0 || fsec != 0)
                                910                 :                :             {
                                911                 :             10 :                 *cp++ = ' ';
                                912   [ +  -  -  +  :             10 :                 if (sec < 0 || (sec == 0 && fsec < 0))
                                              -  - ]
                                913                 :                :                 {
 5618 meskes@postgresql.or      914         [ #  # ]:UBC           0 :                     if (is_zero)
 2433 peter_e@gmx.net           915                 :              0 :                         is_before = true;
 5618 meskes@postgresql.or      916         [ #  # ]:              0 :                     else if (!is_before)
                                917                 :              0 :                         *cp++ = '-';
                                918                 :                :                 }
 5618 meskes@postgresql.or      919         [ -  + ]:CBC          10 :                 else if (is_before)
 5618 meskes@postgresql.or      920                 :UBC           0 :                     *cp++ = '-';
 5618 meskes@postgresql.or      921                 :CBC          10 :                 AppendSeconds(cp, sec, fsec, MAX_INTERVAL_PRECISION, false);
 7686                           922                 :             10 :                 cp += strlen(cp);
                                923                 :                :                 /* We output "ago", not negatives, so use abs(). */
 5618                           924                 :             10 :                 sprintf(cp, " sec%s",
                                925   [ +  +  -  + ]:             10 :                         (abs(sec) != 1 || fsec != 0) ? "s" : "");
 2433 peter_e@gmx.net           926                 :             10 :                 is_zero = false;
                                927                 :                :             }
                                928                 :                :             /* identically zero? then put in a unitless zero... */
 5618 meskes@postgresql.or      929         [ -  + ]:             54 :             if (is_zero)
 5618 meskes@postgresql.or      930                 :UBC           0 :                 strcat(cp, " 0");
 5618 meskes@postgresql.or      931         [ -  + ]:CBC          54 :             if (is_before)
 5618 meskes@postgresql.or      932                 :UBC           0 :                 strcat(cp, " ago");
 7686 meskes@postgresql.or      933                 :CBC          54 :             break;
                                934                 :                :     }
 2407 peter_e@gmx.net           935                 :             54 : }
                                936                 :                : 
                                937                 :                : 
                                938                 :                : /* interval2tm()
                                939                 :                :  * Convert an interval data type to a tm structure.
                                940                 :                :  */
                                941                 :                : static int
 2489 tgl@sss.pgh.pa.us         942                 :             54 : interval2tm(interval span, struct tm *tm, fsec_t *fsec)
                                943                 :                : {
                                944                 :                :     int64       time;
                                945                 :                : 
 7686 meskes@postgresql.or      946         [ +  + ]:             54 :     if (span.month != 0)
                                947                 :                :     {
 6842 bruce@momjian.us          948                 :              3 :         tm->tm_year = span.month / MONTHS_PER_YEAR;
                                949                 :              3 :         tm->tm_mon = span.month % MONTHS_PER_YEAR;
                                950                 :                :     }
                                951                 :                :     else
                                952                 :                :     {
 7686 meskes@postgresql.or      953                 :             51 :         tm->tm_year = 0;
                                954                 :             51 :         tm->tm_mon = 0;
                                955                 :                :     }
                                956                 :                : 
                                957                 :             54 :     time = span.time;
                                958                 :                : 
 6764 bruce@momjian.us          959                 :             54 :     tm->tm_mday = time / USECS_PER_DAY;
                                960                 :             54 :     time -= tm->tm_mday * USECS_PER_DAY;
                                961                 :             54 :     tm->tm_hour = time / USECS_PER_HOUR;
                                962                 :             54 :     time -= tm->tm_hour * USECS_PER_HOUR;
                                963                 :             54 :     tm->tm_min = time / USECS_PER_MINUTE;
                                964                 :             54 :     time -= tm->tm_min * USECS_PER_MINUTE;
                                965                 :             54 :     tm->tm_sec = time / USECS_PER_SEC;
                                966                 :             54 :     *fsec = time - (tm->tm_sec * USECS_PER_SEC);
                                967                 :                : 
 7686 meskes@postgresql.or      968                 :             54 :     return 0;
                                969                 :                : }                               /* interval2tm() */
                                970                 :                : 
                                971                 :                : static int
 2489 tgl@sss.pgh.pa.us         972                 :             28 : tm2interval(struct tm *tm, fsec_t fsec, interval * span)
                                973                 :                : {
 3631 bruce@momjian.us          974         [ +  - ]:             28 :     if ((double) tm->tm_year * MONTHS_PER_YEAR + tm->tm_mon > INT_MAX ||
                                975         [ -  + ]:             28 :         (double) tm->tm_year * MONTHS_PER_YEAR + tm->tm_mon < INT_MIN)
 3727 bruce@momjian.us          976                 :UBC           0 :         return -1;
 6842 bruce@momjian.us          977                 :CBC          28 :     span->month = tm->tm_year * MONTHS_PER_YEAR + tm->tm_mon;
                                978                 :             28 :     span->time = (((((((tm->tm_mday * INT64CONST(24)) +
 6756                           979                 :             28 :                        tm->tm_hour) * INT64CONST(60)) +
                                980                 :             28 :                      tm->tm_min) * INT64CONST(60)) +
                                981                 :             28 :                    tm->tm_sec) * USECS_PER_SEC) + fsec;
                                982                 :                : 
 7686 meskes@postgresql.or      983                 :             28 :     return 0;
                                984                 :                : }                               /* tm2interval() */
                                985                 :                : 
                                986                 :                : interval *
 6422                           987                 :             16 : PGTYPESinterval_new(void)
                                988                 :                : {
                                989                 :                :     interval   *result;
                                990                 :                : 
                                991                 :             16 :     result = (interval *) pgtypes_alloc(sizeof(interval));
                                992                 :                :     /* result can be NULL if we run out of memory */
                                993                 :             16 :     return result;
                                994                 :                : }
                                995                 :                : 
                                996                 :                : void
 6402 bruce@momjian.us          997                 :             13 : PGTYPESinterval_free(interval * intvl)
                                998                 :                : {
 6422 meskes@postgresql.or      999                 :             13 :     free(intvl);
                               1000                 :             13 : }
                               1001                 :                : 
                               1002                 :                : interval *
 7684                          1003                 :             29 : PGTYPESinterval_from_asc(char *str, char **endptr)
                               1004                 :                : {
 7523                          1005                 :             29 :     interval   *result = NULL;
                               1006                 :                :     fsec_t      fsec;
                               1007                 :                :     struct tm   tt,
 7686                          1008                 :             29 :                *tm = &tt;
                               1009                 :                :     int         dtype;
                               1010                 :                :     int         nf;
                               1011                 :                :     char       *field[MAXDATEFIELDS];
                               1012                 :                :     int         ftype[MAXDATEFIELDS];
                               1013                 :                :     char        lowstr[MAXDATELEN + MAXDATEFIELDS];
                               1014                 :                :     char       *realptr;
 7559 bruce@momjian.us         1015         [ +  + ]:             29 :     char      **ptr = (endptr != NULL) ? endptr : &realptr;
                               1016                 :                : 
 7686 meskes@postgresql.or     1017                 :             29 :     tm->tm_year = 0;
                               1018                 :             29 :     tm->tm_mon = 0;
                               1019                 :             29 :     tm->tm_mday = 0;
                               1020                 :             29 :     tm->tm_hour = 0;
                               1021                 :             29 :     tm->tm_min = 0;
                               1022                 :             29 :     tm->tm_sec = 0;
                               1023                 :             29 :     fsec = 0;
                               1024                 :                : 
 3709 noah@leadboat.com        1025         [ -  + ]:             29 :     if (strlen(str) > MAXDATELEN)
                               1026                 :                :     {
 7686 meskes@postgresql.or     1027                 :UBC           0 :         errno = PGTYPES_INTVL_BAD_INTERVAL;
                               1028                 :              0 :         return NULL;
                               1029                 :                :     }
                               1030                 :                : 
 5443 meskes@postgresql.or     1031   [ +  -  +  + ]:CBC          58 :     if (ParseDateTime(str, lowstr, field, ftype, &nf, ptr) != 0 ||
 5618                          1032         [ +  - ]:             30 :         (DecodeInterval(field, ftype, nf, &dtype, tm, &fsec) != 0 &&
                               1033                 :              1 :          DecodeISO8601Interval(str, &dtype, tm, &fsec) != 0))
                               1034                 :                :     {
 7686                          1035                 :              1 :         errno = PGTYPES_INTVL_BAD_INTERVAL;
                               1036                 :              1 :         return NULL;
                               1037                 :                :     }
                               1038                 :                : 
 7523                          1039                 :             28 :     result = (interval *) pgtypes_alloc(sizeof(interval));
 7686                          1040         [ -  + ]:             28 :     if (!result)
 7686 meskes@postgresql.or     1041                 :UBC           0 :         return NULL;
                               1042                 :                : 
 7686 meskes@postgresql.or     1043         [ -  + ]:CBC          28 :     if (dtype != DTK_DELTA)
                               1044                 :                :     {
 7686 meskes@postgresql.or     1045                 :UBC           0 :         errno = PGTYPES_INTVL_BAD_INTERVAL;
 7223                          1046                 :              0 :         free(result);
 7686                          1047                 :              0 :         return NULL;
                               1048                 :                :     }
                               1049                 :                : 
 7686 meskes@postgresql.or     1050         [ -  + ]:CBC          28 :     if (tm2interval(tm, fsec, result) != 0)
                               1051                 :                :     {
 7686 meskes@postgresql.or     1052                 :UBC           0 :         errno = PGTYPES_INTVL_BAD_INTERVAL;
 7223                          1053                 :              0 :         free(result);
 7686                          1054                 :              0 :         return NULL;
                               1055                 :                :     }
                               1056                 :                : 
 6522 meskes@postgresql.or     1057                 :CBC          28 :     errno = 0;
 7686                          1058                 :             28 :     return result;
                               1059                 :                : }
                               1060                 :                : 
                               1061                 :                : char *
 6756 bruce@momjian.us         1062                 :             54 : PGTYPESinterval_to_asc(interval * span)
                               1063                 :                : {
                               1064                 :                :     struct tm   tt,
 7686 meskes@postgresql.or     1065                 :             54 :                *tm = &tt;
                               1066                 :                :     fsec_t      fsec;
                               1067                 :                :     char        buf[MAXDATELEN + 1];
 5421 bruce@momjian.us         1068                 :             54 :     int         IntervalStyle = INTSTYLE_POSTGRES_VERBOSE;
                               1069                 :                : 
 7686 meskes@postgresql.or     1070         [ -  + ]:             54 :     if (interval2tm(*span, tm, &fsec) != 0)
                               1071                 :                :     {
 7686 meskes@postgresql.or     1072                 :UBC           0 :         errno = PGTYPES_INTVL_BAD_INTERVAL;
                               1073                 :              0 :         return NULL;
                               1074                 :                :     }
                               1075                 :                : 
 2407 peter_e@gmx.net          1076                 :CBC          54 :     EncodeInterval(tm, fsec, IntervalStyle, buf);
                               1077                 :                : 
 7559 bruce@momjian.us         1078                 :             54 :     return pgtypes_strdup(buf);
                               1079                 :                : }
                               1080                 :                : 
                               1081                 :                : int
 6431 meskes@postgresql.or     1082                 :             17 : PGTYPESinterval_copy(interval * intvlsrc, interval * intvldest)
                               1083                 :                : {
                               1084                 :             17 :     intvldest->time = intvlsrc->time;
                               1085                 :             17 :     intvldest->month = intvlsrc->month;
                               1086                 :                : 
 7686                          1087                 :             17 :     return 0;
                               1088                 :                : }
        

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