LCOV - code coverage report
Current view: top level - src/interfaces/ecpg/pgtypeslib - interval.c (source / functions) Coverage Total Hit
Test: Code coverage Lines: 0.0 % 638 0
Test Date: 2026-01-26 10:56:24 Functions: 0.0 % 19 0
Legend: Lines:     hit not hit

            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            0 : AdjustFractSeconds(double frac, struct /* pg_ */ tm *tm, fsec_t *fsec, int scale)
      24              : {
      25            0 :         int                     sec;
      26              : 
      27            0 :         if (frac == 0)
      28            0 :                 return;
      29            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            0 : }
      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            0 :         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            0 : }
      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            0 :         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            0 : }
      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            0 : ClearPgTm(struct /* pg_ */ tm *tm, fsec_t *fsec)
      95              : {
      96            0 :         tm->tm_year = 0;
      97            0 :         tm->tm_mon = 0;
      98            0 :         tm->tm_mday = 0;
      99            0 :         tm->tm_hour = 0;
     100            0 :         tm->tm_min = 0;
     101            0 :         tm->tm_sec = 0;
     102            0 :         *fsec = 0;
     103            0 : }
     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            0 : DecodeISO8601Interval(char *str,
     113              :                                           int *dtype, struct /* pg_ */ tm *tm, fsec_t *fsec)
     114              : {
     115            0 :         bool            datepart = true;
     116            0 :         bool            havefield = false;
     117              : 
     118            0 :         *dtype = DTK_DELTA;
     119            0 :         ClearPgTm(tm, fsec);
     120              : 
     121            0 :         if (strlen(str) < 2 || str[0] != 'P')
     122            0 :                 return DTERR_BAD_FORMAT;
     123              : 
     124            0 :         str++;
     125            0 :         while (*str)
     126              :         {
     127            0 :                 char       *fieldstart;
     128            0 :                 int                     val;
     129            0 :                 double          fval;
     130            0 :                 char            unit;
     131            0 :                 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              :                                 case 'Y':
     157            0 :                                         tm->tm_year += val;
     158            0 :                                         tm->tm_mon += rint(fval * MONTHS_PER_YEAR);
     159            0 :                                         break;
     160              :                                 case 'M':
     161            0 :                                         tm->tm_mon += val;
     162            0 :                                         AdjustFractDays(fval, tm, fsec, DAYS_PER_MONTH);
     163            0 :                                         break;
     164              :                                 case 'W':
     165            0 :                                         tm->tm_mday += val * 7;
     166            0 :                                         AdjustFractDays(fval, tm, fsec, 7);
     167            0 :                                         break;
     168              :                                 case 'D':
     169            0 :                                         tm->tm_mday += val;
     170            0 :                                         AdjustFractSeconds(fval, tm, fsec, SECS_PER_DAY);
     171            0 :                                         break;
     172              :                                 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              :                                 default:
     236              :                                         /* not a valid date unit suffix */
     237            0 :                                         return DTERR_BAD_FORMAT;
     238              :                         }
     239            0 :                 }
     240              :                 else
     241              :                 {
     242            0 :                         switch (unit)           /* after T: H M S */
     243              :                         {
     244              :                                 case 'H':
     245            0 :                                         tm->tm_hour += val;
     246            0 :                                         AdjustFractSeconds(fval, tm, fsec, SECS_PER_HOUR);
     247            0 :                                         break;
     248              :                                 case 'M':
     249            0 :                                         tm->tm_min += val;
     250            0 :                                         AdjustFractSeconds(fval, tm, fsec, SECS_PER_MINUTE);
     251            0 :                                         break;
     252              :                                 case 'S':
     253            0 :                                         tm->tm_sec += val;
     254            0 :                                         AdjustFractSeconds(fval, tm, fsec, 1);
     255            0 :                                         break;
     256              :                                 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              :                                 default:
     298              :                                         /* not a valid time unit suffix */
     299            0 :                                         return DTERR_BAD_FORMAT;
     300              :                         }
     301              :                 }
     302              : 
     303            0 :                 havefield = true;
     304            0 :         }
     305              : 
     306            0 :         return 0;
     307            0 : }
     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            0 : DecodeInterval(char **field, int *ftype, int nf,        /* int range, */
     327              :                            int *dtype, struct /* pg_ */ tm *tm, fsec_t *fsec)
     328              : {
     329            0 :         int                     IntervalStyle = INTSTYLE_POSTGRES_VERBOSE;
     330            0 :         int                     range = INTERVAL_FULL_RANGE;
     331            0 :         bool            is_before = false;
     332            0 :         char       *cp;
     333            0 :         int                     fmask = 0,
     334              :                                 tmask,
     335              :                                 type;
     336            0 :         int                     i;
     337            0 :         int                     dterr;
     338            0 :         int                     val;
     339            0 :         double          fval;
     340              : 
     341            0 :         *dtype = DTK_DELTA;
     342            0 :         type = IGNORE_DTF;
     343            0 :         ClearPgTm(tm, fsec);
     344              : 
     345              :         /* read through list backwards to pick up units before values */
     346            0 :         for (i = nf - 1; i >= 0; i--)
     347              :         {
     348            0 :                 switch (ftype[i])
     349              :                 {
     350              :                         case DTK_TIME:
     351            0 :                                 dterr = DecodeTime(field[i],    /* range, */
     352            0 :                                                                    &tmask, tm, fsec);
     353            0 :                                 if (dterr)
     354            0 :                                         return dterr;
     355            0 :                                 type = DTK_DAY;
     356            0 :                                 break;
     357              : 
     358              :                         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            0 :                                                            &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            0 :                                         }
     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            0 :                                 if (type == IGNORE_DTF)
     399              :                                 {
     400              :                                         /* use typmod to decide what rightmost field is */
     401            0 :                                         switch (range)
     402              :                                         {
     403              :                                                 case INTERVAL_MASK(YEAR):
     404            0 :                                                         type = DTK_YEAR;
     405            0 :                                                         break;
     406              :                                                 case INTERVAL_MASK(MONTH):
     407              :                                                 case INTERVAL_MASK(YEAR) | INTERVAL_MASK(MONTH):
     408            0 :                                                         type = DTK_MONTH;
     409            0 :                                                         break;
     410              :                                                 case INTERVAL_MASK(DAY):
     411            0 :                                                         type = DTK_DAY;
     412            0 :                                                         break;
     413              :                                                 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              :                                                 case INTERVAL_MASK(MINUTE):
     420              :                                                 case INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE):
     421            0 :                                                         type = DTK_MINUTE;
     422            0 :                                                         break;
     423              :                                                 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              :                                                 default:
     429            0 :                                                         type = DTK_SECOND;
     430            0 :                                                         break;
     431              :                                         }
     432            0 :                                 }
     433              : 
     434            0 :                                 errno = 0;
     435            0 :                                 val = strtoint(field[i], &cp, 10);
     436            0 :                                 if (errno == ERANGE)
     437            0 :                                         return DTERR_FIELD_OVERFLOW;
     438              : 
     439            0 :                                 if (*cp == '-')
     440              :                                 {
     441              :                                         /* SQL "years-months" syntax */
     442            0 :                                         int                     val2;
     443              : 
     444            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            0 :                                 }
     455            0 :                                 else if (*cp == '.')
     456              :                                 {
     457            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            0 :                                 }
     465            0 :                                 else if (*cp == '\0')
     466            0 :                                         fval = 0;
     467              :                                 else
     468            0 :                                         return DTERR_BAD_FORMAT;
     469              : 
     470            0 :                                 tmask = 0;              /* DTK_M(type); */
     471              : 
     472            0 :                                 switch (type)
     473              :                                 {
     474              :                                         case DTK_MICROSEC:
     475            0 :                                                 *fsec += rint(val + fval);
     476            0 :                                                 tmask = DTK_M(MICROSECOND);
     477            0 :                                                 break;
     478              : 
     479              :                                         case DTK_MILLISEC:
     480            0 :                                                 *fsec += rint((val + fval) * 1000);
     481            0 :                                                 tmask = DTK_M(MILLISECOND);
     482            0 :                                                 break;
     483              : 
     484              :                                         case DTK_SECOND:
     485            0 :                                                 tm->tm_sec += val;
     486            0 :                                                 *fsec += rint(fval * 1000000);
     487              : 
     488              :                                                 /*
     489              :                                                  * If any subseconds were specified, consider this
     490              :                                                  * microsecond and millisecond input as well.
     491              :                                                  */
     492            0 :                                                 if (fval == 0)
     493            0 :                                                         tmask = DTK_M(SECOND);
     494              :                                                 else
     495            0 :                                                         tmask = DTK_ALL_SECS_M;
     496            0 :                                                 break;
     497              : 
     498              :                                         case DTK_MINUTE:
     499            0 :                                                 tm->tm_min += val;
     500            0 :                                                 AdjustFractSeconds(fval, tm, fsec, SECS_PER_MINUTE);
     501            0 :                                                 tmask = DTK_M(MINUTE);
     502            0 :                                                 break;
     503              : 
     504              :                                         case DTK_HOUR:
     505            0 :                                                 tm->tm_hour += val;
     506            0 :                                                 AdjustFractSeconds(fval, tm, fsec, SECS_PER_HOUR);
     507            0 :                                                 tmask = DTK_M(HOUR);
     508            0 :                                                 type = DTK_DAY;
     509            0 :                                                 break;
     510              : 
     511              :                                         case DTK_DAY:
     512            0 :                                                 tm->tm_mday += val;
     513            0 :                                                 AdjustFractSeconds(fval, tm, fsec, SECS_PER_DAY);
     514            0 :                                                 tmask = (fmask & DTK_M(DAY)) ? 0 : DTK_M(DAY);
     515            0 :                                                 break;
     516              : 
     517              :                                         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              :                                         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              :                                         case DTK_YEAR:
     530            0 :                                                 tm->tm_year += val;
     531            0 :                                                 tm->tm_mon += rint(fval * MONTHS_PER_YEAR);
     532            0 :                                                 tmask = (fmask & DTK_M(YEAR)) ? 0 : DTK_M(YEAR);
     533            0 :                                                 break;
     534              : 
     535              :                                         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              :                                         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              :                                         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              :                                         default:
     554            0 :                                                 return DTERR_BAD_FORMAT;
     555              :                                 }
     556            0 :                                 break;
     557              : 
     558              :                         case DTK_STRING:
     559              :                         case DTK_SPECIAL:
     560            0 :                                 type = DecodeUnits(i, field[i], &val);
     561            0 :                                 if (type == IGNORE_DTF)
     562            0 :                                         continue;
     563              : 
     564            0 :                                 tmask = 0;              /* DTK_M(type); */
     565            0 :                                 switch (type)
     566              :                                 {
     567              :                                         case UNITS:
     568            0 :                                                 type = val;
     569            0 :                                                 break;
     570              : 
     571              :                                         case AGO:
     572            0 :                                                 is_before = true;
     573            0 :                                                 type = val;
     574            0 :                                                 break;
     575              : 
     576              :                                         case RESERV:
     577            0 :                                                 tmask = (DTK_DATE_M | DTK_TIME_M);
     578            0 :                                                 *dtype = val;
     579            0 :                                                 break;
     580              : 
     581              :                                         default:
     582            0 :                                                 return DTERR_BAD_FORMAT;
     583              :                                 }
     584            0 :                                 break;
     585              : 
     586              :                         default:
     587            0 :                                 return DTERR_BAD_FORMAT;
     588              :                 }
     589              : 
     590            0 :                 if (tmask & fmask)
     591            0 :                         return DTERR_BAD_FORMAT;
     592            0 :                 fmask |= tmask;
     593            0 :         }
     594              : 
     595              :         /* ensure that at least one time field has been found */
     596            0 :         if (fmask == 0)
     597            0 :                 return DTERR_BAD_FORMAT;
     598              : 
     599              :         /* ensure fractional seconds are fractional */
     600            0 :         if (*fsec != 0)
     601              :         {
     602            0 :                 int                     sec;
     603              : 
     604            0 :                 sec = *fsec / USECS_PER_SEC;
     605            0 :                 *fsec -= sec * USECS_PER_SEC;
     606            0 :                 tm->tm_sec += sec;
     607            0 :         }
     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            0 :         if (IntervalStyle == INTSTYLE_SQL_STANDARD && *field[0] == '-')
     626              :         {
     627              :                 /* Check for additional explicit signs */
     628            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            0 :                 }
     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            0 :                 }
     660            0 :         }
     661              : 
     662              :         /* finally, AGO negates everything */
     663            0 :         if (is_before)
     664              :         {
     665            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            0 :         }
     673              : 
     674            0 :         return 0;
     675            0 : }
     676              : 
     677              : 
     678              : /* copy&pasted from .../src/backend/utils/adt/datetime.c */
     679              : static char *
     680            0 : AddVerboseIntPart(char *cp, int value, const char *units,
     681              :                                   bool *is_zero, bool *is_before)
     682              : {
     683            0 :         if (value == 0)
     684            0 :                 return cp;
     685              :         /* first nonzero value sets is_before */
     686            0 :         if (*is_zero)
     687              :         {
     688            0 :                 *is_before = (value < 0);
     689            0 :                 value = abs(value);
     690            0 :         }
     691            0 :         else if (*is_before)
     692            0 :                 value = -value;
     693            0 :         sprintf(cp, " %d %s%s", value, units, (value == 1) ? "" : "s");
     694            0 :         *is_zero = false;
     695            0 :         return cp + strlen(cp);
     696            0 : }
     697              : 
     698              : /* copy&pasted from .../src/backend/utils/adt/datetime.c */
     699              : static char *
     700            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            0 :                         value,
     709            0 :                         units,
     710            0 :                         (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            0 : }
     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            0 : }
     730              : 
     731              : /* copy&pasted from .../src/backend/utils/adt/datetime.c */
     732              : static void
     733            0 : AppendSeconds(char *cp, int sec, fsec_t fsec, int precision, bool fillzeros)
     734              : {
     735            0 :         if (fsec == 0)
     736              :         {
     737            0 :                 if (fillzeros)
     738            0 :                         sprintf(cp, "%02d", abs(sec));
     739              :                 else
     740            0 :                         sprintf(cp, "%d", abs(sec));
     741            0 :         }
     742              :         else
     743              :         {
     744            0 :                 if (fillzeros)
     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));
     748            0 :                 TrimTrailingZeros(cp);
     749              :         }
     750            0 : }
     751              : 
     752              : 
     753              : /* copy&pasted from .../src/backend/utils/adt/datetime.c
     754              :  *
     755              :  * Change pg_tm to tm
     756              :  */
     757              : 
     758              : void
     759            0 : EncodeInterval(struct /* pg_ */ tm *tm, fsec_t fsec, int style, char *str)
     760              : {
     761            0 :         char       *cp = str;
     762            0 :         int                     year = tm->tm_year;
     763            0 :         int                     mon = tm->tm_mon;
     764            0 :         int                     mday = tm->tm_mday;
     765            0 :         int                     hour = tm->tm_hour;
     766            0 :         int                     min = tm->tm_min;
     767            0 :         int                     sec = tm->tm_sec;
     768            0 :         bool            is_before = false;
     769            0 :         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            0 :         switch (style)
     778              :         {
     779              :                         /* SQL Standard interval format */
     780              :                 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            0 :                                 }
     810              : 
     811            0 :                                 if (!has_negative && !has_positive)
     812              :                                 {
     813            0 :                                         sprintf(cp, "0");
     814            0 :                                 }
     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            0 :                                                         year_sign, abs(year), abs(mon),
     829            0 :                                                         day_sign, abs(mday),
     830            0 :                                                         sec_sign, abs(hour), abs(min));
     831            0 :                                         cp += strlen(cp);
     832            0 :                                         AppendSeconds(cp, sec, fsec, MAX_INTERVAL_PRECISION, true);
     833            0 :                                 }
     834            0 :                                 else if (has_year_month)
     835              :                                 {
     836            0 :                                         sprintf(cp, "%d-%d", year, mon);
     837            0 :                                 }
     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            0 :                                 }
     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            0 :                         }
     851            0 :                         break;
     852              : 
     853              :                         /* ISO 8601 "time-intervals by duration only" */
     854              :                 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            0 :                         }
     879            0 :                         break;
     880              : 
     881              :                         /* Compatible with postgresql < 8.4 when DateStyle = 'iso' */
     882              :                 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            0 :                                                 abs(hour), abs(min));
     894            0 :                                 cp += strlen(cp);
     895            0 :                                 AppendSeconds(cp, sec, fsec, MAX_INTERVAL_PRECISION, true);
     896            0 :                         }
     897            0 :                         break;
     898              : 
     899              :                         /* Compatible with postgresql < 8.4 when DateStyle != 'iso' */
     900            0 :                 case INTSTYLE_POSTGRES_VERBOSE:
     901              :                 default:
     902            0 :                         strcpy(cp, "@");
     903            0 :                         cp++;
     904            0 :                         cp = AddVerboseIntPart(cp, year, "year", &is_zero, &is_before);
     905            0 :                         cp = AddVerboseIntPart(cp, mon, "mon", &is_zero, &is_before);
     906            0 :                         cp = AddVerboseIntPart(cp, mday, "day", &is_zero, &is_before);
     907            0 :                         cp = AddVerboseIntPart(cp, hour, "hour", &is_zero, &is_before);
     908            0 :                         cp = AddVerboseIntPart(cp, min, "min", &is_zero, &is_before);
     909            0 :                         if (sec != 0 || fsec != 0)
     910              :                         {
     911            0 :                                 *cp++ = ' ';
     912            0 :                                 if (sec < 0 || (sec == 0 && fsec < 0))
     913              :                                 {
     914            0 :                                         if (is_zero)
     915            0 :                                                 is_before = true;
     916            0 :                                         else if (!is_before)
     917            0 :                                                 *cp++ = '-';
     918            0 :                                 }
     919            0 :                                 else if (is_before)
     920            0 :                                         *cp++ = '-';
     921            0 :                                 AppendSeconds(cp, sec, fsec, MAX_INTERVAL_PRECISION, false);
     922            0 :                                 cp += strlen(cp);
     923              :                                 /* We output "ago", not negatives, so use abs(). */
     924            0 :                                 sprintf(cp, " sec%s",
     925            0 :                                                 (abs(sec) != 1 || fsec != 0) ? "s" : "");
     926            0 :                                 is_zero = false;
     927            0 :                         }
     928              :                         /* identically zero? then put in a unitless zero... */
     929            0 :                         if (is_zero)
     930            0 :                                 strcat(cp, " 0");
     931            0 :                         if (is_before)
     932            0 :                                 strcat(cp, " ago");
     933            0 :                         break;
     934              :         }
     935            0 : }
     936              : 
     937              : 
     938              : /* interval2tm()
     939              :  * Convert an interval data type to a tm structure.
     940              :  */
     941              : static int
     942            0 : interval2tm(interval span, struct tm *tm, fsec_t *fsec)
     943              : {
     944            0 :         int64           time;
     945              : 
     946            0 :         if (span.month != 0)
     947              :         {
     948            0 :                 tm->tm_year = span.month / MONTHS_PER_YEAR;
     949            0 :                 tm->tm_mon = span.month % MONTHS_PER_YEAR;
     950            0 :         }
     951              :         else
     952              :         {
     953            0 :                 tm->tm_year = 0;
     954            0 :                 tm->tm_mon = 0;
     955              :         }
     956              : 
     957            0 :         time = span.time;
     958              : 
     959            0 :         tm->tm_mday = time / USECS_PER_DAY;
     960            0 :         time -= tm->tm_mday * USECS_PER_DAY;
     961            0 :         tm->tm_hour = time / USECS_PER_HOUR;
     962            0 :         time -= tm->tm_hour * USECS_PER_HOUR;
     963            0 :         tm->tm_min = time / USECS_PER_MINUTE;
     964            0 :         time -= tm->tm_min * USECS_PER_MINUTE;
     965            0 :         tm->tm_sec = time / USECS_PER_SEC;
     966            0 :         *fsec = time - (tm->tm_sec * USECS_PER_SEC);
     967              : 
     968            0 :         return 0;
     969            0 : }                                                               /* interval2tm() */
     970              : 
     971              : static int
     972            0 : tm2interval(struct tm *tm, fsec_t fsec, interval * span)
     973              : {
     974            0 :         if ((double) tm->tm_year * MONTHS_PER_YEAR + tm->tm_mon > INT_MAX ||
     975            0 :                 (double) tm->tm_year * MONTHS_PER_YEAR + tm->tm_mon < INT_MIN)
     976            0 :                 return -1;
     977            0 :         span->month = tm->tm_year * MONTHS_PER_YEAR + tm->tm_mon;
     978            0 :         span->time = (((((((tm->tm_mday * INT64CONST(24)) +
     979            0 :                                            tm->tm_hour) * INT64CONST(60)) +
     980            0 :                                          tm->tm_min) * INT64CONST(60)) +
     981            0 :                                    tm->tm_sec) * USECS_PER_SEC) + fsec;
     982              : 
     983            0 :         return 0;
     984            0 : }                                                               /* tm2interval() */
     985              : 
     986              : interval *
     987            0 : PGTYPESinterval_new(void)
     988              : {
     989            0 :         interval   *result;
     990              : 
     991            0 :         result = (interval *) pgtypes_alloc(sizeof(interval));
     992              :         /* result can be NULL if we run out of memory */
     993            0 :         return result;
     994            0 : }
     995              : 
     996              : void
     997            0 : PGTYPESinterval_free(interval * intvl)
     998              : {
     999            0 :         free(intvl);
    1000            0 : }
    1001              : 
    1002              : interval *
    1003            0 : PGTYPESinterval_from_asc(char *str, char **endptr)
    1004              : {
    1005            0 :         interval   *result = NULL;
    1006            0 :         fsec_t          fsec;
    1007            0 :         struct tm       tt,
    1008            0 :                            *tm = &tt;
    1009            0 :         int                     dtype;
    1010            0 :         int                     nf;
    1011            0 :         char       *field[MAXDATEFIELDS];
    1012            0 :         int                     ftype[MAXDATEFIELDS];
    1013            0 :         char            lowstr[MAXDATELEN + MAXDATEFIELDS];
    1014            0 :         char       *realptr;
    1015            0 :         char      **ptr = (endptr != NULL) ? endptr : &realptr;
    1016              : 
    1017            0 :         tm->tm_year = 0;
    1018            0 :         tm->tm_mon = 0;
    1019            0 :         tm->tm_mday = 0;
    1020            0 :         tm->tm_hour = 0;
    1021            0 :         tm->tm_min = 0;
    1022            0 :         tm->tm_sec = 0;
    1023            0 :         fsec = 0;
    1024              : 
    1025            0 :         if (strlen(str) > MAXDATELEN)
    1026              :         {
    1027            0 :                 errno = PGTYPES_INTVL_BAD_INTERVAL;
    1028            0 :                 return NULL;
    1029              :         }
    1030              : 
    1031            0 :         if (ParseDateTime(str, lowstr, field, ftype, &nf, ptr) != 0 ||
    1032            0 :                 (DecodeInterval(field, ftype, nf, &dtype, tm, &fsec) != 0 &&
    1033            0 :                  DecodeISO8601Interval(str, &dtype, tm, &fsec) != 0))
    1034              :         {
    1035            0 :                 errno = PGTYPES_INTVL_BAD_INTERVAL;
    1036            0 :                 return NULL;
    1037              :         }
    1038              : 
    1039            0 :         result = (interval *) pgtypes_alloc(sizeof(interval));
    1040            0 :         if (!result)
    1041            0 :                 return NULL;
    1042              : 
    1043            0 :         if (dtype != DTK_DELTA)
    1044              :         {
    1045            0 :                 errno = PGTYPES_INTVL_BAD_INTERVAL;
    1046            0 :                 free(result);
    1047            0 :                 return NULL;
    1048              :         }
    1049              : 
    1050            0 :         if (tm2interval(tm, fsec, result) != 0)
    1051              :         {
    1052            0 :                 errno = PGTYPES_INTVL_BAD_INTERVAL;
    1053            0 :                 free(result);
    1054            0 :                 return NULL;
    1055              :         }
    1056              : 
    1057            0 :         errno = 0;
    1058            0 :         return result;
    1059            0 : }
    1060              : 
    1061              : char *
    1062            0 : PGTYPESinterval_to_asc(interval * span)
    1063              : {
    1064            0 :         struct tm       tt,
    1065            0 :                            *tm = &tt;
    1066            0 :         fsec_t          fsec;
    1067            0 :         char            buf[MAXDATELEN + 1];
    1068            0 :         int                     IntervalStyle = INTSTYLE_POSTGRES_VERBOSE;
    1069              : 
    1070            0 :         if (interval2tm(*span, tm, &fsec) != 0)
    1071              :         {
    1072            0 :                 errno = PGTYPES_INTVL_BAD_INTERVAL;
    1073            0 :                 return NULL;
    1074              :         }
    1075              : 
    1076            0 :         EncodeInterval(tm, fsec, IntervalStyle, buf);
    1077              : 
    1078            0 :         return pgtypes_strdup(buf);
    1079            0 : }
    1080              : 
    1081              : int
    1082            0 : PGTYPESinterval_copy(interval * intvlsrc, interval * intvldest)
    1083              : {
    1084            0 :         intvldest->time = intvlsrc->time;
    1085            0 :         intvldest->month = intvlsrc->month;
    1086              : 
    1087            0 :         return 0;
    1088              : }
        

Generated by: LCOV version 2.3.2-1