LCOV - differential code coverage report
Current view: top level - src/interfaces/ecpg/pgtypeslib - interval.c (source / functions) Coverage Total Hit UNC UBC GNC CBC DUB
Current: Differential Code Coverage HEAD vs 15 Lines: 33.1 % 602 199 2 401 199 2
Current Date: 2023-04-08 15:15:32 Functions: 73.7 % 19 14 5 1 13
Baseline: 15
Baseline Date: 2023-04-08 15:09:40
Legend: Lines: hit not hit

           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
      23 CBC          38 : AdjustFractSeconds(double frac, struct /* pg_ */ tm *tm, fsec_t *fsec, int scale)
      24                 : {
      25                 :     int         sec;
      26                 : 
      27              38 :     if (frac == 0)
      28              38 :         return;
      29 UBC           0 :     frac *= scale;
      30               0 :     sec = (int) frac;
      31               0 :     tm->tm_sec += sec;
      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
      41               0 : AdjustFractDays(double frac, struct /* pg_ */ tm *tm, fsec_t *fsec, int scale)
      42                 : {
      43                 :     int         extra_days;
      44                 : 
      45               0 :     if (frac == 0)
      46               0 :         return;
      47               0 :     frac *= scale;
      48               0 :     extra_days = (int) frac;
      49               0 :     tm->tm_mday += extra_days;
      50               0 :     frac -= extra_days;
      51               0 :     AdjustFractSeconds(frac, tm, fsec, SECS_PER_DAY);
      52                 : }
      53                 : 
      54                 : /* copy&pasted from .../src/backend/utils/adt/datetime.c */
      55                 : static int
      56               0 : ParseISO8601Number(const char *str, char **endptr, int *ipart, double *fpart)
      57                 : {
      58                 :     double      val;
      59                 : 
      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
      81               0 : ISO8601IntegerWidth(const char *fieldstart)
      82                 : {
      83                 :     /* We might have had a leading '-' */
      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
      94 CBC          30 : ClearPgTm(struct /* pg_ */ tm *tm, fsec_t *fsec)
      95                 : {
      96              30 :     tm->tm_year = 0;
      97              30 :     tm->tm_mon = 0;
      98              30 :     tm->tm_mday = 0;
      99              30 :     tm->tm_hour = 0;
     100              30 :     tm->tm_min = 0;
     101              30 :     tm->tm_sec = 0;
     102              30 :     *fsec = 0;
     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                 : {
     115               1 :     bool        datepart = true;
     116               1 :     bool        havefield = false;
     117                 : 
     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                 : 
     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                 : 
     133               0 :         if (*str == 'T')        /* T indicates the beginning of the time part */
     134                 :         {
     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                 :         {
     154               0 :             switch (unit)       /* before T: Y M W D */
     155                 :             {
     156               0 :                 case 'Y':
     157               0 :                     tm->tm_year += val;
     158               0 :                     tm->tm_mon += rint(fval * MONTHS_PER_YEAR);
     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;
     172               0 :                 case 'T':       /* ISO 8601 4.4.3.3 Alternative Format / Basic */
     173                 :                 case '\0':
     174               0 :                     if (ISO8601IntegerWidth(fieldstart) == 8 && !havefield)
     175                 :                     {
     176               0 :                         tm->tm_year += val / 10000;
     177               0 :                         tm->tm_mon += (val / 100) % 100;
     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;
     194               0 :                     tm->tm_mon += rint(fval * MONTHS_PER_YEAR);
     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;
     207               0 :                     tm->tm_mon += val;
     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                 :         {
     242               0 :             switch (unit)       /* after T: H M S */
     243                 :             {
     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;
     256               0 :                 case '\0':      /* ISO 8601 4.4.3.3 Alternative Format */
     257               0 :                     if (ISO8601IntegerWidth(fieldstart) == 6 && !havefield)
     258                 :                     {
     259               0 :                         tm->tm_hour += val / 10000;
     260               0 :                         tm->tm_min += (val / 100) % 100;
     261               0 :                         tm->tm_sec += val % 100;
     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;
     280               0 :                     tm->tm_min += val;
     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;
     291               0 :                     tm->tm_sec += val;
     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
     326 CBC          29 : DecodeInterval(char **field, int *ftype, int nf,    /* int range, */
     327                 :                int *dtype, struct /* pg_ */ tm *tm, fsec_t *fsec)
     328                 : {
     329              29 :     int         IntervalStyle = INTSTYLE_POSTGRES_VERBOSE;
     330              29 :     int         range = INTERVAL_FULL_RANGE;
     331              29 :     bool        is_before = false;
     332                 :     char       *cp;
     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;
     343              29 :     ClearPgTm(tm, fsec);
     344                 : 
     345                 :     /* read through list backwards to pick up units before values */
     346             117 :     for (i = nf - 1; i >= 0; i--)
     347                 :     {
     348              89 :         switch (ftype[i])
     349                 :         {
     350               1 :             case DTK_TIME:
     351               1 :                 dterr = DecodeTime(field[i],    /* range, */
     352                 :                                    &tmask, tm, fsec);
     353               1 :                 if (dterr)
     354 UBC           0 :                     return dterr;
     355 CBC           1 :                 type = DTK_DAY;
     356               1 :                 break;
     357                 : 
     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                 :                  */
     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                 :                  */
     372               0 :                 if (strchr(field[i] + 1, ':') != NULL &&
     373               0 :                     DecodeTime(field[i] + 1,    /* INTERVAL_FULL_RANGE, */
     374                 :                                &tmask, tm, fsec) == 0)
     375                 :                 {
     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:
     398 CBC          44 :                 if (type == IGNORE_DTF)
     399                 :                 {
     400                 :                     /* use typmod to decide what rightmost field is */
     401                 :                     switch (range)
     402                 :                     {
     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                 : 
     434 CBC          44 :                 errno = 0;
     435              44 :                 val = strtoint(field[i], &cp, 10);
     436              44 :                 if (errno == ERANGE)
     437 UBC           0 :                     return DTERR_FIELD_OVERFLOW;
     438                 : 
     439 CBC          44 :                 if (*cp == '-')
     440                 :                 {
     441                 :                     /* SQL "years-months" syntax */
     442                 :                     int         val2;
     443                 : 
     444 UBC           0 :                     val2 = strtoint(cp + 1, &cp, 10);
     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                 :                 }
     455 CBC          44 :                 else if (*cp == '.')
     456                 :                 {
     457 UBC           0 :                     errno = 0;
     458               0 :                     fval = strtod(cp, &cp);
     459               0 :                     if (*cp != '\0' || errno != 0)
     460               0 :                         return DTERR_BAD_FORMAT;
     461                 : 
     462               0 :                     if (*field[i] == '-')
     463               0 :                         fval = -fval;
     464                 :                 }
     465 CBC          44 :                 else if (*cp == '\0')
     466              44 :                     fval = 0;
     467                 :                 else
     468 UBC           0 :                     return DTERR_BAD_FORMAT;
     469                 : 
     470 CBC          44 :                 tmask = 0;      /* DTK_M(type); */
     471                 : 
     472                 :                 switch (type)
     473                 :                 {
     474 UBC           0 :                     case DTK_MICROSEC:
     475               0 :                         *fsec += rint(val + fval);
     476               0 :                         tmask = DTK_M(MICROSECOND);
     477               0 :                         break;
     478                 : 
     479               0 :                     case DTK_MILLISEC:
     480               0 :                         *fsec += rint((val + fval) * 1000);
     481               0 :                         tmask = DTK_M(MILLISECOND);
     482               0 :                         break;
     483                 : 
     484 CBC           5 :                     case DTK_SECOND:
     485               5 :                         tm->tm_sec += val;
     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
     495 UBC           0 :                             tmask = DTK_ALL_SECS_M;
     496 CBC           5 :                         break;
     497                 : 
     498               7 :                     case DTK_MINUTE:
     499               7 :                         tm->tm_min += val;
     500               7 :                         AdjustFractSeconds(fval, tm, fsec, SECS_PER_MINUTE);
     501               7 :                         tmask = DTK_M(MINUTE);
     502               7 :                         break;
     503                 : 
     504              25 :                     case DTK_HOUR:
     505              25 :                         tm->tm_hour += val;
     506              25 :                         AdjustFractSeconds(fval, tm, fsec, SECS_PER_HOUR);
     507              25 :                         tmask = DTK_M(HOUR);
     508              25 :                         type = DTK_DAY;
     509              25 :                         break;
     510                 : 
     511               6 :                     case DTK_DAY:
     512               6 :                         tm->tm_mday += val;
     513               6 :                         AdjustFractSeconds(fval, tm, fsec, SECS_PER_DAY);
     514               6 :                         tmask = (fmask & DTK_M(DAY)) ? 0 : DTK_M(DAY);
     515               6 :                         break;
     516                 : 
     517 UBC           0 :                     case DTK_WEEK:
     518               0 :                         tm->tm_mday += val * 7;
     519               0 :                         AdjustFractDays(fval, tm, fsec, 7);
     520               0 :                         tmask = (fmask & DTK_M(DAY)) ? 0 : DTK_M(DAY);
     521               0 :                         break;
     522                 : 
     523               0 :                     case DTK_MONTH:
     524               0 :                         tm->tm_mon += val;
     525               0 :                         AdjustFractDays(fval, tm, fsec, DAYS_PER_MONTH);
     526               0 :                         tmask = DTK_M(MONTH);
     527               0 :                         break;
     528                 : 
     529 CBC           1 :                     case DTK_YEAR:
     530               1 :                         tm->tm_year += val;
     531               1 :                         tm->tm_mon += rint(fval * MONTHS_PER_YEAR);
     532               1 :                         tmask = (fmask & DTK_M(YEAR)) ? 0 : DTK_M(YEAR);
     533               1 :                         break;
     534                 : 
     535 UBC           0 :                     case DTK_DECADE:
     536               0 :                         tm->tm_year += val * 10;
     537               0 :                         tm->tm_mon += rint(fval * MONTHS_PER_YEAR * 10);
     538               0 :                         tmask = (fmask & DTK_M(YEAR)) ? 0 : DTK_M(YEAR);
     539               0 :                         break;
     540                 : 
     541               0 :                     case DTK_CENTURY:
     542               0 :                         tm->tm_year += val * 100;
     543               0 :                         tm->tm_mon += rint(fval * MONTHS_PER_YEAR * 100);
     544               0 :                         tmask = (fmask & DTK_M(YEAR)) ? 0 : DTK_M(YEAR);
     545               0 :                         break;
     546                 : 
     547               0 :                     case DTK_MILLENNIUM:
     548               0 :                         tm->tm_year += val * 1000;
     549               0 :                         tm->tm_mon += rint(fval * MONTHS_PER_YEAR * 1000);
     550               0 :                         tmask = (fmask & DTK_M(YEAR)) ? 0 : DTK_M(YEAR);
     551               0 :                         break;
     552                 : 
     553               0 :                     default:
     554               0 :                         return DTERR_BAD_FORMAT;
     555                 :                 }
     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)
     562 UBC           0 :                     continue;
     563                 : 
     564 CBC          44 :                 tmask = 0;      /* DTK_M(type); */
     565                 :                 switch (type)
     566                 :                 {
     567              43 :                     case UNITS:
     568              43 :                         type = val;
     569              43 :                         break;
     570                 : 
     571 UBC           0 :                     case AGO:
     572               0 :                         is_before = true;
     573               0 :                         type = val;
     574               0 :                         break;
     575                 : 
     576               0 :                     case RESERV:
     577               0 :                         tmask = (DTK_DATE_M | DTK_TIME_M);
     578               0 :                         *dtype = val;
     579               0 :                         break;
     580                 : 
     581 CBC           1 :                     default:
     582               1 :                         return DTERR_BAD_FORMAT;
     583                 :                 }
     584              43 :                 break;
     585                 : 
     586 UBC           0 :             default:
     587               0 :                 return DTERR_BAD_FORMAT;
     588                 :         }
     589                 : 
     590 CBC          88 :         if (tmask & fmask)
     591 UBC           0 :             return DTERR_BAD_FORMAT;
     592 CBC          88 :         fmask |= tmask;
     593                 :     }
     594                 : 
     595                 :     /* ensure that at least one time field has been found */
     596              28 :     if (fmask == 0)
     597 UBC           0 :         return DTERR_BAD_FORMAT;
     598                 : 
     599                 :     /* ensure fractional seconds are fractional */
     600 CBC          28 :     if (*fsec != 0)
     601                 :     {
     602                 :         int         sec;
     603                 : 
     604 UBC           0 :         sec = *fsec / USECS_PER_SEC;
     605               0 :         *fsec -= sec * USECS_PER_SEC;
     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                 :      */
     625 CBC          28 :     if (IntervalStyle == INTSTYLE_SQL_STANDARD && *field[0] == '-')
     626                 :     {
     627                 :         /* Check for additional explicit signs */
     628 UBC           0 :         bool        more_signs = false;
     629                 : 
     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 */
     663 CBC          28 :     if (is_before)
     664                 :     {
     665 UBC           0 :         *fsec = -(*fsec);
     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                 : 
     674 CBC          28 :     return 0;
     675                 : }
     676                 : 
     677                 : 
     678                 : /* copy&pasted from .../src/backend/utils/adt/datetime.c */
     679                 : static char *
     680             265 : AddVerboseIntPart(char *cp, int value, const char *units,
     681                 :                   bool *is_zero, bool *is_before)
     682                 : {
     683             265 :     if (value == 0)
     684             192 :         return cp;
     685                 :     /* first nonzero value sets is_before */
     686              73 :     if (*is_zero)
     687                 :     {
     688              53 :         *is_before = (value < 0);
     689              53 :         value = abs(value);
     690                 :     }
     691              20 :     else if (*is_before)
     692 UBC           0 :         value = -value;
     693 CBC          73 :     sprintf(cp, " %d %s%s", value, units, (value == 1) ? "" : "s");
     694              73 :     *is_zero = false;
     695              73 :     return cp + strlen(cp);
     696                 : }
     697                 : 
     698                 : /* copy&pasted from .../src/backend/utils/adt/datetime.c */
     699                 : static char *
     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);
     717               0 :     *is_zero = false;
     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
     733 CBC           9 : AppendSeconds(char *cp, int sec, fsec_t fsec, int precision, bool fillzeros)
     734                 : {
     735               9 :     if (fsec == 0)
     736                 :     {
     737               9 :         if (fillzeros)
     738 UBC           0 :             sprintf(cp, "%02d", abs(sec));
     739                 :         else
     740 CBC           9 :             sprintf(cp, "%d", abs(sec));
     741                 :     }
     742                 :     else
     743                 :     {
     744 UBC           0 :         if (fillzeros)
     745 UNC           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));
     748 UBC           0 :         TrimTrailingZeros(cp);
     749                 :     }
     750 CBC           9 : }
     751                 : 
     752                 : 
     753                 : /* copy&pasted from .../src/backend/utils/adt/datetime.c
     754                 :  *
     755                 :  * Change pg_tm to tm
     756                 :  */
     757                 : 
     758                 : void
     759              53 : EncodeInterval(struct /* pg_ */ tm *tm, fsec_t fsec, int style, char *str)
     760                 : {
     761              53 :     char       *cp = str;
     762              53 :     int         year = tm->tm_year;
     763              53 :     int         mon = tm->tm_mon;
     764              53 :     int         mday = tm->tm_mday;
     765              53 :     int         hour = tm->tm_hour;
     766              53 :     int         min = tm->tm_min;
     767              53 :     int         sec = tm->tm_sec;
     768              53 :     bool        is_before = false;
     769              53 :     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                 :      */
     777              53 :     switch (style)
     778                 :     {
     779                 :             /* SQL Standard interval format */
     780 UBC           0 :         case INTSTYLE_SQL_STANDARD:
     781                 :             {
     782               0 :                 bool        has_negative = year < 0 || mon < 0 ||
     783               0 :                 mday < 0 || hour < 0 ||
     784               0 :                 min < 0 || sec < 0 || fsec < 0;
     785               0 :                 bool        has_positive = year > 0 || mon > 0 ||
     786               0 :                 mday > 0 || hour > 0 ||
     787               0 :                 min > 0 || sec > 0 || fsec > 0;
     788               0 :                 bool        has_year_month = year != 0 || mon != 0;
     789               0 :                 bool        has_day_time = mday != 0 || hour != 0 ||
     790               0 :                 min != 0 || sec != 0 || fsec != 0;
     791               0 :                 bool        has_day = mday != 0;
     792               0 :                 bool        sql_standard_value = !(has_negative && has_positive) &&
     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                 :                  */
     799               0 :                 if (has_negative && sql_standard_value)
     800                 :                 {
     801               0 :                     *cp++ = '-';
     802               0 :                     year = -year;
     803               0 :                     mon = -mon;
     804               0 :                     mday = -mday;
     805               0 :                     hour = -hour;
     806               0 :                     min = -min;
     807               0 :                     sec = -sec;
     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                 :                      */
     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                 : 
     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));
     831               0 :                     cp += strlen(cp);
     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);
     841               0 :                     cp += strlen(cp);
     842               0 :                     AppendSeconds(cp, sec, fsec, MAX_INTERVAL_PRECISION, true);
     843                 :                 }
     844                 :                 else
     845                 :                 {
     846               0 :                     sprintf(cp, "%d:%02d:", hour, min);
     847               0 :                     cp += strlen(cp);
     848               0 :                     AppendSeconds(cp, sec, fsec, MAX_INTERVAL_PRECISION, true);
     849                 :                 }
     850                 :             }
     851               0 :             break;
     852                 : 
     853                 :             /* ISO 8601 "time-intervals by duration only" */
     854               0 :         case INTSTYLE_ISO_8601:
     855                 :             /* special-case zero to avoid printing nothing */
     856               0 :             if (year == 0 && mon == 0 && mday == 0 &&
     857               0 :                 hour == 0 && min == 0 && sec == 0 && fsec == 0)
     858                 :             {
     859               0 :                 sprintf(cp, "PT0S");
     860               0 :                 break;
     861                 :             }
     862               0 :             *cp++ = 'P';
     863               0 :             cp = AddISO8601IntPart(cp, year, 'Y');
     864               0 :             cp = AddISO8601IntPart(cp, mon, 'M');
     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');
     869               0 :             cp = AddISO8601IntPart(cp, min, 'M');
     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);
     875               0 :                 cp += strlen(cp);
     876               0 :                 *cp++ = 'S';
     877               0 :                 *cp = '\0';
     878                 :             }
     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                 :             {
     888               0 :                 bool        minus = (hour < 0 || min < 0 || sec < 0 || fsec < 0);
     889                 : 
     890               0 :                 sprintf(cp, "%s%s%02d:%02d:",
     891               0 :                         is_zero ? "" : " ",
     892               0 :                         (minus ? "-" : (is_before ? "+" : "")),
     893                 :                         abs(hour), abs(min));
     894               0 :                 cp += strlen(cp);
     895               0 :                 AppendSeconds(cp, sec, fsec, MAX_INTERVAL_PRECISION, true);
     896                 :             }
     897               0 :             break;
     898                 : 
     899                 :             /* Compatible with postgresql < 8.4 when DateStyle != 'iso' */
     900 CBC          53 :         case INTSTYLE_POSTGRES_VERBOSE:
     901                 :         default:
     902              53 :             strcpy(cp, "@");
     903              53 :             cp++;
     904              53 :             cp = AddVerboseIntPart(cp, year, "year", &is_zero, &is_before);
     905              53 :             cp = AddVerboseIntPart(cp, mon, "mon", &is_zero, &is_before);
     906              53 :             cp = AddVerboseIntPart(cp, mday, "day", &is_zero, &is_before);
     907              53 :             cp = AddVerboseIntPart(cp, hour, "hour", &is_zero, &is_before);
     908              53 :             cp = AddVerboseIntPart(cp, min, "min", &is_zero, &is_before);
     909              53 :             if (sec != 0 || fsec != 0)
     910                 :             {
     911               9 :                 *cp++ = ' ';
     912               9 :                 if (sec < 0 || (sec == 0 && fsec < 0))
     913                 :                 {
     914 UBC           0 :                     if (is_zero)
     915               0 :                         is_before = true;
     916               0 :                     else if (!is_before)
     917               0 :                         *cp++ = '-';
     918                 :                 }
     919 CBC           9 :                 else if (is_before)
     920 UBC           0 :                     *cp++ = '-';
     921 CBC           9 :                 AppendSeconds(cp, sec, fsec, MAX_INTERVAL_PRECISION, false);
     922               9 :                 cp += strlen(cp);
     923                 :                 /* We output "ago", not negatives, so use abs(). */
     924               9 :                 sprintf(cp, " sec%s",
     925               9 :                         (abs(sec) != 1 || fsec != 0) ? "s" : "");
     926               9 :                 is_zero = false;
     927                 :             }
     928                 :             /* identically zero? then put in a unitless zero... */
     929              53 :             if (is_zero)
     930 UBC           0 :                 strcat(cp, " 0");
     931 CBC          53 :             if (is_before)
     932 UBC           0 :                 strcat(cp, " ago");
     933 CBC          53 :             break;
     934                 :     }
     935              53 : }
     936                 : 
     937                 : 
     938                 : /* interval2tm()
     939                 :  * Convert an interval data type to a tm structure.
     940                 :  */
     941                 : static int
     942              53 : interval2tm(interval span, struct tm *tm, fsec_t *fsec)
     943                 : {
     944                 :     int64       time;
     945                 : 
     946              53 :     if (span.month != 0)
     947                 :     {
     948               2 :         tm->tm_year = span.month / MONTHS_PER_YEAR;
     949               2 :         tm->tm_mon = span.month % MONTHS_PER_YEAR;
     950                 :     }
     951                 :     else
     952                 :     {
     953              51 :         tm->tm_year = 0;
     954              51 :         tm->tm_mon = 0;
     955                 :     }
     956                 : 
     957              53 :     time = span.time;
     958                 : 
     959              53 :     tm->tm_mday = time / USECS_PER_DAY;
     960              53 :     time -= tm->tm_mday * USECS_PER_DAY;
     961              53 :     tm->tm_hour = time / USECS_PER_HOUR;
     962              53 :     time -= tm->tm_hour * USECS_PER_HOUR;
     963              53 :     tm->tm_min = time / USECS_PER_MINUTE;
     964              53 :     time -= tm->tm_min * USECS_PER_MINUTE;
     965              53 :     tm->tm_sec = time / USECS_PER_SEC;
     966              53 :     *fsec = time - (tm->tm_sec * USECS_PER_SEC);
     967                 : 
     968              53 :     return 0;
     969                 : }                               /* interval2tm() */
     970                 : 
     971                 : static int
     972              28 : tm2interval(struct tm *tm, fsec_t fsec, interval * span)
     973                 : {
     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)
     976 UBC           0 :         return -1;
     977 CBC          28 :     span->month = tm->tm_year * MONTHS_PER_YEAR + tm->tm_mon;
     978              28 :     span->time = (((((((tm->tm_mday * INT64CONST(24)) +
     979              28 :                        tm->tm_hour) * INT64CONST(60)) +
     980              28 :                      tm->tm_min) * INT64CONST(60)) +
     981              28 :                    tm->tm_sec) * USECS_PER_SEC) + fsec;
     982                 : 
     983              28 :     return 0;
     984                 : }                               /* tm2interval() */
     985                 : 
     986                 : interval *
     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
     997              13 : PGTYPESinterval_free(interval * intvl)
     998                 : {
     999              13 :     free(intvl);
    1000              13 : }
    1001                 : 
    1002                 : interval *
    1003              29 : PGTYPESinterval_from_asc(char *str, char **endptr)
    1004                 : {
    1005              29 :     interval   *result = NULL;
    1006                 :     fsec_t      fsec;
    1007                 :     struct tm   tt,
    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;
    1015              29 :     char      **ptr = (endptr != NULL) ? endptr : &realptr;
    1016                 : 
    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                 : 
    1025              29 :     if (strlen(str) > MAXDATELEN)
    1026                 :     {
    1027 UBC           0 :         errno = PGTYPES_INTVL_BAD_INTERVAL;
    1028               0 :         return NULL;
    1029                 :     }
    1030                 : 
    1031 CBC          58 :     if (ParseDateTime(str, lowstr, field, ftype, &nf, ptr) != 0 ||
    1032              30 :         (DecodeInterval(field, ftype, nf, &dtype, tm, &fsec) != 0 &&
    1033               1 :          DecodeISO8601Interval(str, &dtype, tm, &fsec) != 0))
    1034                 :     {
    1035               1 :         errno = PGTYPES_INTVL_BAD_INTERVAL;
    1036               1 :         return NULL;
    1037                 :     }
    1038                 : 
    1039              28 :     result = (interval *) pgtypes_alloc(sizeof(interval));
    1040              28 :     if (!result)
    1041 UBC           0 :         return NULL;
    1042                 : 
    1043 CBC          28 :     if (dtype != DTK_DELTA)
    1044                 :     {
    1045 UBC           0 :         errno = PGTYPES_INTVL_BAD_INTERVAL;
    1046               0 :         free(result);
    1047               0 :         return NULL;
    1048                 :     }
    1049                 : 
    1050 CBC          28 :     if (tm2interval(tm, fsec, result) != 0)
    1051                 :     {
    1052 UBC           0 :         errno = PGTYPES_INTVL_BAD_INTERVAL;
    1053               0 :         free(result);
    1054               0 :         return NULL;
    1055                 :     }
    1056                 : 
    1057 CBC          28 :     errno = 0;
    1058              28 :     return result;
    1059                 : }
    1060                 : 
    1061                 : char *
    1062              53 : PGTYPESinterval_to_asc(interval * span)
    1063                 : {
    1064                 :     struct tm   tt,
    1065              53 :                *tm = &tt;
    1066                 :     fsec_t      fsec;
    1067                 :     char        buf[MAXDATELEN + 1];
    1068              53 :     int         IntervalStyle = INTSTYLE_POSTGRES_VERBOSE;
    1069                 : 
    1070              53 :     if (interval2tm(*span, tm, &fsec) != 0)
    1071                 :     {
    1072 UBC           0 :         errno = PGTYPES_INTVL_BAD_INTERVAL;
    1073               0 :         return NULL;
    1074                 :     }
    1075                 : 
    1076 CBC          53 :     EncodeInterval(tm, fsec, IntervalStyle, buf);
    1077                 : 
    1078              53 :     return pgtypes_strdup(buf);
    1079                 : }
    1080                 : 
    1081                 : int
    1082              17 : PGTYPESinterval_copy(interval * intvlsrc, interval * intvldest)
    1083                 : {
    1084              17 :     intvldest->time = intvlsrc->time;
    1085              17 :     intvldest->month = intvlsrc->month;
    1086                 : 
    1087              17 :     return 0;
    1088                 : }
        

Generated by: LCOV version v1.16-55-g56c0a2a