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

            Line data    Source code
       1              : /*
       2              :  * src/interfaces/ecpg/pgtypeslib/timestamp.c
       3              :  */
       4              : #include "postgres_fe.h"
       5              : 
       6              : #include <time.h>
       7              : #include <limits.h>
       8              : #include <math.h>
       9              : 
      10              : #ifdef __FAST_MATH__
      11              : #error -ffast-math is known to break this code
      12              : #endif
      13              : 
      14              : #include "common/int.h"
      15              : #include "dt.h"
      16              : #include "pgtypes_date.h"
      17              : #include "pgtypes_timestamp.h"
      18              : #include "pgtypeslib_extern.h"
      19              : 
      20              : static int64
      21            0 : time2t(const int hour, const int min, const int sec, const fsec_t fsec)
      22              : {
      23            0 :         return (((((hour * MINS_PER_HOUR) + min) * SECS_PER_MINUTE) + sec) * USECS_PER_SEC) + fsec;
      24              : }                                                               /* time2t() */
      25              : 
      26              : static timestamp
      27            0 : dt2local(timestamp dt, int tz)
      28              : {
      29            0 :         dt -= (tz * USECS_PER_SEC);
      30            0 :         return dt;
      31              : }                                                               /* dt2local() */
      32              : 
      33              : /* tm2timestamp()
      34              :  * Convert a tm structure to a timestamp data type.
      35              :  * Note that year is _not_ 1900-based, but is an explicit full value.
      36              :  * Also, month is one-based, _not_ zero-based.
      37              :  *
      38              :  * Returns -1 on failure (overflow).
      39              :  */
      40              : int
      41            0 : tm2timestamp(struct tm *tm, fsec_t fsec, int *tzp, timestamp * result)
      42              : {
      43            0 :         int                     dDate;
      44            0 :         int64           time;
      45              : 
      46              :         /* Prevent overflow in Julian-day routines */
      47            0 :         if (!IS_VALID_JULIAN(tm->tm_year, tm->tm_mon, tm->tm_mday))
      48            0 :                 return -1;
      49              : 
      50            0 :         dDate = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - date2j(2000, 1, 1);
      51            0 :         time = time2t(tm->tm_hour, tm->tm_min, tm->tm_sec, fsec);
      52            0 :         if (unlikely(pg_mul_s64_overflow(dDate, USECS_PER_DAY, result) ||
      53              :                                  pg_add_s64_overflow(*result, time, result)))
      54            0 :                 return -1;
      55            0 :         if (tzp != NULL)
      56            0 :                 *result = dt2local(*result, -(*tzp));
      57              : 
      58              :         /* final range check catches just-out-of-range timestamps */
      59            0 :         if (!IS_VALID_TIMESTAMP(*result))
      60            0 :                 return -1;
      61              : 
      62            0 :         return 0;
      63            0 : }                                                               /* tm2timestamp() */
      64              : 
      65              : static timestamp
      66            0 : SetEpochTimestamp(void)
      67              : {
      68            0 :         int64           noresult = 0;
      69            0 :         timestamp       dt;
      70            0 :         struct tm       tt,
      71            0 :                            *tm = &tt;
      72              : 
      73            0 :         if (GetEpochTime(tm) < 0)
      74            0 :                 return noresult;
      75              : 
      76            0 :         tm2timestamp(tm, 0, NULL, &dt);
      77            0 :         return dt;
      78            0 : }                                                               /* SetEpochTimestamp() */
      79              : 
      80              : /* timestamp2tm()
      81              :  * Convert timestamp data type to POSIX time structure.
      82              :  * Note that year is _not_ 1900-based, but is an explicit full value.
      83              :  * Also, month is one-based, _not_ zero-based.
      84              :  * Returns:
      85              :  *       0 on success
      86              :  *      -1 on out of range
      87              :  *
      88              :  * For dates within the system-supported time_t range, convert to the
      89              :  *      local time zone. If out of this range, leave as GMT. - tgl 97/05/27
      90              :  */
      91              : static int
      92            0 : timestamp2tm(timestamp dt, int *tzp, struct tm *tm, fsec_t *fsec, const char **tzn)
      93              : {
      94            0 :         int64           dDate,
      95              :                                 date0;
      96            0 :         int64           time;
      97              : #if defined(HAVE_STRUCT_TM_TM_ZONE) || defined(HAVE_INT_TIMEZONE)
      98            0 :         time_t          utime;
      99            0 :         struct tm  *tx;
     100              : #endif
     101              : 
     102            0 :         date0 = date2j(2000, 1, 1);
     103              : 
     104            0 :         time = dt;
     105            0 :         TMODULO(time, dDate, USECS_PER_DAY);
     106              : 
     107            0 :         if (time < INT64CONST(0))
     108              :         {
     109            0 :                 time += USECS_PER_DAY;
     110            0 :                 dDate -= 1;
     111            0 :         }
     112              : 
     113              :         /* add offset to go from J2000 back to standard Julian date */
     114            0 :         dDate += date0;
     115              : 
     116              :         /* Julian day routine does not work for negative Julian days */
     117            0 :         if (dDate < 0 || dDate > (timestamp) INT_MAX)
     118            0 :                 return -1;
     119              : 
     120            0 :         j2date((int) dDate, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
     121            0 :         dt2time(time, &tm->tm_hour, &tm->tm_min, &tm->tm_sec, fsec);
     122              : 
     123            0 :         if (tzp != NULL)
     124              :         {
     125              :                 /*
     126              :                  * Does this fall within the capabilities of the localtime()
     127              :                  * interface? Then use this to rotate to the local time zone.
     128              :                  */
     129            0 :                 if (IS_VALID_UTIME(tm->tm_year, tm->tm_mon, tm->tm_mday))
     130              :                 {
     131              : #if defined(HAVE_STRUCT_TM_TM_ZONE) || defined(HAVE_INT_TIMEZONE)
     132            0 :                         struct tm       tmbuf;
     133              : 
     134            0 :                         utime = dt / USECS_PER_SEC +
     135            0 :                                 ((date0 - date2j(1970, 1, 1)) * INT64CONST(86400));
     136              : 
     137            0 :                         tx = localtime_r(&utime, &tmbuf);
     138            0 :                         tm->tm_year = tx->tm_year + 1900;
     139            0 :                         tm->tm_mon = tx->tm_mon + 1;
     140            0 :                         tm->tm_mday = tx->tm_mday;
     141            0 :                         tm->tm_hour = tx->tm_hour;
     142            0 :                         tm->tm_min = tx->tm_min;
     143            0 :                         tm->tm_isdst = tx->tm_isdst;
     144              : 
     145              : #if defined(HAVE_STRUCT_TM_TM_ZONE)
     146            0 :                         tm->tm_gmtoff = tx->tm_gmtoff;
     147            0 :                         tm->tm_zone = tx->tm_zone;
     148              : 
     149            0 :                         *tzp = -tm->tm_gmtoff;       /* tm_gmtoff is Sun/DEC-ism */
     150            0 :                         if (tzn != NULL)
     151            0 :                                 *tzn = tm->tm_zone;
     152              : #elif defined(HAVE_INT_TIMEZONE)
     153              :                         *tzp = (tm->tm_isdst > 0) ? TIMEZONE_GLOBAL - SECS_PER_HOUR : TIMEZONE_GLOBAL;
     154              :                         if (tzn != NULL)
     155              :                                 *tzn = TZNAME_GLOBAL[(tm->tm_isdst > 0)];
     156              : #endif
     157              : #else                                                   /* not (HAVE_STRUCT_TM_TM_ZONE ||
     158              :                                                                  * HAVE_INT_TIMEZONE) */
     159              :                         *tzp = 0;
     160              :                         /* Mark this as *no* time zone available */
     161              :                         tm->tm_isdst = -1;
     162              :                         if (tzn != NULL)
     163              :                                 *tzn = NULL;
     164              : #endif
     165            0 :                 }
     166              :                 else
     167              :                 {
     168            0 :                         *tzp = 0;
     169              :                         /* Mark this as *no* time zone available */
     170            0 :                         tm->tm_isdst = -1;
     171            0 :                         if (tzn != NULL)
     172            0 :                                 *tzn = NULL;
     173              :                 }
     174            0 :         }
     175              :         else
     176              :         {
     177            0 :                 tm->tm_isdst = -1;
     178            0 :                 if (tzn != NULL)
     179            0 :                         *tzn = NULL;
     180              :         }
     181              : 
     182            0 :         tm->tm_yday = dDate - date2j(tm->tm_year, 1, 1) + 1;
     183              : 
     184            0 :         return 0;
     185            0 : }                                                               /* timestamp2tm() */
     186              : 
     187              : /* EncodeSpecialTimestamp()
     188              :  *      * Convert reserved timestamp data type to string.
     189              :  *       */
     190              : static void
     191            0 : EncodeSpecialTimestamp(timestamp dt, char *str)
     192              : {
     193            0 :         if (TIMESTAMP_IS_NOBEGIN(dt))
     194            0 :                 strcpy(str, EARLY);
     195            0 :         else if (TIMESTAMP_IS_NOEND(dt))
     196            0 :                 strcpy(str, LATE);
     197              :         else
     198            0 :                 abort();                                /* shouldn't happen */
     199            0 : }
     200              : 
     201              : timestamp
     202            0 : PGTYPEStimestamp_from_asc(char *str, char **endptr)
     203              : {
     204            0 :         timestamp       result;
     205            0 :         int64           noresult = 0;
     206            0 :         fsec_t          fsec;
     207            0 :         struct tm       tt,
     208            0 :                            *tm = &tt;
     209            0 :         int                     dtype;
     210            0 :         int                     nf;
     211            0 :         char       *field[MAXDATEFIELDS];
     212            0 :         int                     ftype[MAXDATEFIELDS];
     213            0 :         char            lowstr[MAXDATELEN + MAXDATEFIELDS];
     214            0 :         char       *realptr;
     215            0 :         char      **ptr = (endptr != NULL) ? endptr : &realptr;
     216              : 
     217            0 :         if (strlen(str) > MAXDATELEN)
     218              :         {
     219            0 :                 errno = PGTYPES_TS_BAD_TIMESTAMP;
     220            0 :                 return noresult;
     221              :         }
     222              : 
     223            0 :         if (ParseDateTime(str, lowstr, field, ftype, &nf, ptr) != 0 ||
     224            0 :                 DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, 0) != 0)
     225              :         {
     226            0 :                 errno = PGTYPES_TS_BAD_TIMESTAMP;
     227            0 :                 return noresult;
     228              :         }
     229              : 
     230            0 :         switch (dtype)
     231              :         {
     232              :                 case DTK_DATE:
     233            0 :                         if (tm2timestamp(tm, fsec, NULL, &result) != 0)
     234              :                         {
     235            0 :                                 errno = PGTYPES_TS_BAD_TIMESTAMP;
     236            0 :                                 return noresult;
     237              :                         }
     238            0 :                         break;
     239              : 
     240              :                 case DTK_EPOCH:
     241            0 :                         result = SetEpochTimestamp();
     242            0 :                         break;
     243              : 
     244              :                 case DTK_LATE:
     245            0 :                         TIMESTAMP_NOEND(result);
     246            0 :                         break;
     247              : 
     248              :                 case DTK_EARLY:
     249            0 :                         TIMESTAMP_NOBEGIN(result);
     250            0 :                         break;
     251              : 
     252              :                 default:
     253            0 :                         errno = PGTYPES_TS_BAD_TIMESTAMP;
     254            0 :                         return noresult;
     255              :         }
     256              : 
     257              :         /* AdjustTimestampForTypmod(&result, typmod); */
     258              : 
     259              :         /*
     260              :          * Since it's difficult to test for noresult, make sure errno is 0 if no
     261              :          * error occurred.
     262              :          */
     263            0 :         errno = 0;
     264            0 :         return result;
     265            0 : }
     266              : 
     267              : char *
     268            0 : PGTYPEStimestamp_to_asc(timestamp tstamp)
     269              : {
     270            0 :         struct tm       tt,
     271            0 :                            *tm = &tt;
     272            0 :         char            buf[MAXDATELEN + 1];
     273            0 :         fsec_t          fsec;
     274            0 :         int                     DateStyle = 1;  /* this defaults to USE_ISO_DATES, shall we
     275              :                                                                  * make it an option? */
     276              : 
     277            0 :         if (TIMESTAMP_NOT_FINITE(tstamp))
     278            0 :                 EncodeSpecialTimestamp(tstamp, buf);
     279            0 :         else if (timestamp2tm(tstamp, NULL, tm, &fsec, NULL) == 0)
     280            0 :                 EncodeDateTime(tm, fsec, false, 0, NULL, DateStyle, buf, 0);
     281              :         else
     282              :         {
     283            0 :                 errno = PGTYPES_TS_BAD_TIMESTAMP;
     284            0 :                 return NULL;
     285              :         }
     286            0 :         return pgtypes_strdup(buf);
     287            0 : }
     288              : 
     289              : void
     290            0 : PGTYPEStimestamp_current(timestamp * ts)
     291              : {
     292            0 :         struct tm       tm;
     293              : 
     294            0 :         GetCurrentDateTime(&tm);
     295            0 :         if (errno == 0)
     296            0 :                 tm2timestamp(&tm, 0, NULL, ts);
     297            0 : }
     298              : 
     299              : static int
     300            0 : dttofmtasc_replace(timestamp * ts, date dDate, int dow, struct tm *tm,
     301              :                                    char *output, int *pstr_len, const char *fmtstr)
     302              : {
     303            0 :         union un_fmt_comb replace_val;
     304            0 :         int                     replace_type;
     305            0 :         int                     i;
     306            0 :         const char *p = fmtstr;
     307            0 :         char       *q = output;
     308              : 
     309            0 :         while (*p)
     310              :         {
     311            0 :                 if (*p == '%')
     312              :                 {
     313            0 :                         p++;
     314              :                         /* fix compiler warning */
     315            0 :                         replace_type = PGTYPES_TYPE_NOTHING;
     316            0 :                         switch (*p)
     317              :                         {
     318              :                                         /* the abbreviated name of the day in the week */
     319              :                                         /* XXX should be locale aware */
     320              :                                 case 'a':
     321            0 :                                         replace_val.str_val = pgtypes_date_weekdays_short[dow];
     322            0 :                                         replace_type = PGTYPES_TYPE_STRING_CONSTANT;
     323            0 :                                         break;
     324              :                                         /* the full name of the day in the week */
     325              :                                         /* XXX should be locale aware */
     326              :                                 case 'A':
     327            0 :                                         replace_val.str_val = days[dow];
     328            0 :                                         replace_type = PGTYPES_TYPE_STRING_CONSTANT;
     329            0 :                                         break;
     330              :                                         /* the abbreviated name of the month */
     331              :                                         /* XXX should be locale aware */
     332              :                                 case 'b':
     333              :                                 case 'h':
     334            0 :                                         replace_val.str_val = months[tm->tm_mon - 1];
     335            0 :                                         replace_type = PGTYPES_TYPE_STRING_CONSTANT;
     336            0 :                                         break;
     337              :                                         /* the full name of the month */
     338              :                                         /* XXX should be locale aware */
     339              :                                 case 'B':
     340            0 :                                         replace_val.str_val = pgtypes_date_months[tm->tm_mon - 1];
     341            0 :                                         replace_type = PGTYPES_TYPE_STRING_CONSTANT;
     342            0 :                                         break;
     343              : 
     344              :                                         /*
     345              :                                          * The preferred date and time representation for the
     346              :                                          * current locale.
     347              :                                          */
     348              :                                 case 'c':
     349              :                                         /* XXX */
     350              :                                         break;
     351              :                                         /* the century number with leading zeroes */
     352              :                                 case 'C':
     353            0 :                                         replace_val.uint_val = tm->tm_year / 100;
     354            0 :                                         replace_type = PGTYPES_TYPE_UINT_2_LZ;
     355            0 :                                         break;
     356              :                                         /* day with leading zeroes (01 - 31) */
     357              :                                 case 'd':
     358            0 :                                         replace_val.uint_val = tm->tm_mday;
     359            0 :                                         replace_type = PGTYPES_TYPE_UINT_2_LZ;
     360            0 :                                         break;
     361              :                                         /* the date in the format mm/dd/yy */
     362              :                                 case 'D':
     363              : 
     364              :                                         /*
     365              :                                          * ts, dDate, dow, tm is information about the timestamp
     366              :                                          *
     367              :                                          * q is the start of the current output buffer
     368              :                                          *
     369              :                                          * pstr_len is a pointer to the remaining size of output,
     370              :                                          * i.e. the size of q
     371              :                                          */
     372            0 :                                         i = dttofmtasc_replace(ts, dDate, dow, tm,
     373            0 :                                                                                    q, pstr_len,
     374              :                                                                                    "%m/%d/%y");
     375            0 :                                         if (i)
     376            0 :                                                 return i;
     377            0 :                                         break;
     378              :                                         /* day with leading spaces (01 - 31) */
     379              :                                 case 'e':
     380            0 :                                         replace_val.uint_val = tm->tm_mday;
     381            0 :                                         replace_type = PGTYPES_TYPE_UINT_2_LS;
     382            0 :                                         break;
     383              : 
     384              :                                         /*
     385              :                                          * alternative format modifier
     386              :                                          */
     387              :                                 case 'E':
     388              :                                         {
     389            0 :                                                 char            tmp[4] = "%Ex";
     390              : 
     391            0 :                                                 p++;
     392            0 :                                                 if (*p == '\0')
     393            0 :                                                         return -1;
     394            0 :                                                 tmp[2] = *p;
     395              : 
     396              :                                                 /*
     397              :                                                  * strftime's month is 0 based, ours is 1 based
     398              :                                                  */
     399            0 :                                                 tm->tm_mon -= 1;
     400            0 :                                                 i = strftime(q, *pstr_len, tmp, tm);
     401            0 :                                                 if (i == 0)
     402            0 :                                                         return -1;
     403            0 :                                                 while (*q)
     404              :                                                 {
     405            0 :                                                         q++;
     406            0 :                                                         (*pstr_len)--;
     407              :                                                 }
     408            0 :                                                 tm->tm_mon += 1;
     409            0 :                                                 replace_type = PGTYPES_TYPE_NOTHING;
     410            0 :                                                 break;
     411            0 :                                         }
     412              : 
     413              :                                         /*
     414              :                                          * The ISO 8601 year with century as a decimal number. The
     415              :                                          * 4-digit year corresponding to the ISO week number.
     416              :                                          */
     417              :                                 case 'G':
     418              :                                         {
     419              :                                                 /* Keep compiler quiet - Don't use a literal format */
     420            0 :                                                 const char *fmt = "%G";
     421              : 
     422            0 :                                                 tm->tm_mon -= 1;
     423            0 :                                                 i = strftime(q, *pstr_len, fmt, tm);
     424            0 :                                                 if (i == 0)
     425            0 :                                                         return -1;
     426            0 :                                                 while (*q)
     427              :                                                 {
     428            0 :                                                         q++;
     429            0 :                                                         (*pstr_len)--;
     430              :                                                 }
     431            0 :                                                 tm->tm_mon += 1;
     432            0 :                                                 replace_type = PGTYPES_TYPE_NOTHING;
     433            0 :                                         }
     434            0 :                                         break;
     435              : 
     436              :                                         /*
     437              :                                          * Like %G, but without century, i.e., with a 2-digit year
     438              :                                          * (00-99).
     439              :                                          */
     440              :                                 case 'g':
     441              :                                         {
     442            0 :                                                 const char *fmt = "%g"; /* Keep compiler quiet about
     443              :                                                                                                  * 2-digit year */
     444              : 
     445            0 :                                                 tm->tm_mon -= 1;
     446            0 :                                                 i = strftime(q, *pstr_len, fmt, tm);
     447            0 :                                                 if (i == 0)
     448            0 :                                                         return -1;
     449            0 :                                                 while (*q)
     450              :                                                 {
     451            0 :                                                         q++;
     452            0 :                                                         (*pstr_len)--;
     453              :                                                 }
     454            0 :                                                 tm->tm_mon += 1;
     455            0 :                                                 replace_type = PGTYPES_TYPE_NOTHING;
     456            0 :                                         }
     457            0 :                                         break;
     458              :                                         /* hour (24 hour clock) with leading zeroes */
     459              :                                 case 'H':
     460            0 :                                         replace_val.uint_val = tm->tm_hour;
     461            0 :                                         replace_type = PGTYPES_TYPE_UINT_2_LZ;
     462            0 :                                         break;
     463              :                                         /* hour (12 hour clock) with leading zeroes */
     464              :                                 case 'I':
     465            0 :                                         replace_val.uint_val = tm->tm_hour % 12;
     466            0 :                                         replace_type = PGTYPES_TYPE_UINT_2_LZ;
     467            0 :                                         break;
     468              : 
     469              :                                         /*
     470              :                                          * The day of the year as a decimal number with leading
     471              :                                          * zeroes. It ranges from 001 to 366.
     472              :                                          */
     473              :                                 case 'j':
     474            0 :                                         replace_val.uint_val = tm->tm_yday;
     475            0 :                                         replace_type = PGTYPES_TYPE_UINT_3_LZ;
     476            0 :                                         break;
     477              : 
     478              :                                         /*
     479              :                                          * The hour (24 hour clock). Leading zeroes will be turned
     480              :                                          * into spaces.
     481              :                                          */
     482              :                                 case 'k':
     483            0 :                                         replace_val.uint_val = tm->tm_hour;
     484            0 :                                         replace_type = PGTYPES_TYPE_UINT_2_LS;
     485            0 :                                         break;
     486              : 
     487              :                                         /*
     488              :                                          * The hour (12 hour clock). Leading zeroes will be turned
     489              :                                          * into spaces.
     490              :                                          */
     491              :                                 case 'l':
     492            0 :                                         replace_val.uint_val = tm->tm_hour % 12;
     493            0 :                                         replace_type = PGTYPES_TYPE_UINT_2_LS;
     494            0 :                                         break;
     495              :                                         /* The month as a decimal number with a leading zero */
     496              :                                 case 'm':
     497            0 :                                         replace_val.uint_val = tm->tm_mon;
     498            0 :                                         replace_type = PGTYPES_TYPE_UINT_2_LZ;
     499            0 :                                         break;
     500              :                                         /* The minute as a decimal number with a leading zero */
     501              :                                 case 'M':
     502            0 :                                         replace_val.uint_val = tm->tm_min;
     503            0 :                                         replace_type = PGTYPES_TYPE_UINT_2_LZ;
     504            0 :                                         break;
     505              :                                         /* A newline character */
     506              :                                 case 'n':
     507            0 :                                         replace_val.char_val = '\n';
     508            0 :                                         replace_type = PGTYPES_TYPE_CHAR;
     509            0 :                                         break;
     510              :                                         /* the AM/PM specifier (uppercase) */
     511              :                                         /* XXX should be locale aware */
     512              :                                 case 'p':
     513            0 :                                         if (tm->tm_hour < 12)
     514            0 :                                                 replace_val.str_val = "AM";
     515              :                                         else
     516            0 :                                                 replace_val.str_val = "PM";
     517            0 :                                         replace_type = PGTYPES_TYPE_STRING_CONSTANT;
     518            0 :                                         break;
     519              :                                         /* the AM/PM specifier (lowercase) */
     520              :                                         /* XXX should be locale aware */
     521              :                                 case 'P':
     522            0 :                                         if (tm->tm_hour < 12)
     523            0 :                                                 replace_val.str_val = "am";
     524              :                                         else
     525            0 :                                                 replace_val.str_val = "pm";
     526            0 :                                         replace_type = PGTYPES_TYPE_STRING_CONSTANT;
     527            0 :                                         break;
     528              :                                         /* the time in the format %I:%M:%S %p */
     529              :                                         /* XXX should be locale aware */
     530              :                                 case 'r':
     531            0 :                                         i = dttofmtasc_replace(ts, dDate, dow, tm,
     532            0 :                                                                                    q, pstr_len,
     533              :                                                                                    "%I:%M:%S %p");
     534            0 :                                         if (i)
     535            0 :                                                 return i;
     536            0 :                                         break;
     537              :                                         /* The time in 24 hour notation (%H:%M) */
     538              :                                 case 'R':
     539            0 :                                         i = dttofmtasc_replace(ts, dDate, dow, tm,
     540            0 :                                                                                    q, pstr_len,
     541              :                                                                                    "%H:%M");
     542            0 :                                         if (i)
     543            0 :                                                 return i;
     544            0 :                                         break;
     545              :                                         /* The number of seconds since the Epoch (1970-01-01) */
     546              :                                 case 's':
     547            0 :                                         replace_val.int64_val = (*ts - SetEpochTimestamp()) / 1000000.0;
     548            0 :                                         replace_type = PGTYPES_TYPE_INT64;
     549            0 :                                         break;
     550              :                                         /* seconds as a decimal number with leading zeroes */
     551              :                                 case 'S':
     552            0 :                                         replace_val.uint_val = tm->tm_sec;
     553            0 :                                         replace_type = PGTYPES_TYPE_UINT_2_LZ;
     554            0 :                                         break;
     555              :                                         /* A tabulator */
     556              :                                 case 't':
     557            0 :                                         replace_val.char_val = '\t';
     558            0 :                                         replace_type = PGTYPES_TYPE_CHAR;
     559            0 :                                         break;
     560              :                                         /* The time in 24 hour notation (%H:%M:%S) */
     561              :                                 case 'T':
     562            0 :                                         i = dttofmtasc_replace(ts, dDate, dow, tm,
     563            0 :                                                                                    q, pstr_len,
     564              :                                                                                    "%H:%M:%S");
     565            0 :                                         if (i)
     566            0 :                                                 return i;
     567            0 :                                         break;
     568              : 
     569              :                                         /*
     570              :                                          * The day of the week as a decimal, Monday = 1, Sunday =
     571              :                                          * 7
     572              :                                          */
     573              :                                 case 'u':
     574            0 :                                         replace_val.uint_val = dow;
     575            0 :                                         if (replace_val.uint_val == 0)
     576            0 :                                                 replace_val.uint_val = 7;
     577            0 :                                         replace_type = PGTYPES_TYPE_UINT;
     578            0 :                                         break;
     579              :                                         /* The week number of the year as a decimal number */
     580              :                                 case 'U':
     581            0 :                                         tm->tm_mon -= 1;
     582            0 :                                         i = strftime(q, *pstr_len, "%U", tm);
     583            0 :                                         if (i == 0)
     584            0 :                                                 return -1;
     585            0 :                                         while (*q)
     586              :                                         {
     587            0 :                                                 q++;
     588            0 :                                                 (*pstr_len)--;
     589              :                                         }
     590            0 :                                         tm->tm_mon += 1;
     591            0 :                                         replace_type = PGTYPES_TYPE_NOTHING;
     592            0 :                                         break;
     593              : 
     594              :                                         /*
     595              :                                          * The ISO 8601:1988 week number of the current year as a
     596              :                                          * decimal number.
     597              :                                          */
     598              :                                 case 'V':
     599              :                                         {
     600              :                                                 /* Keep compiler quiet - Don't use a literal format */
     601            0 :                                                 const char *fmt = "%V";
     602              : 
     603            0 :                                                 i = strftime(q, *pstr_len, fmt, tm);
     604            0 :                                                 if (i == 0)
     605            0 :                                                         return -1;
     606            0 :                                                 while (*q)
     607              :                                                 {
     608            0 :                                                         q++;
     609            0 :                                                         (*pstr_len)--;
     610              :                                                 }
     611            0 :                                                 replace_type = PGTYPES_TYPE_NOTHING;
     612            0 :                                         }
     613            0 :                                         break;
     614              : 
     615              :                                         /*
     616              :                                          * The day of the week as a decimal, Sunday being 0 and
     617              :                                          * Monday 1.
     618              :                                          */
     619              :                                 case 'w':
     620            0 :                                         replace_val.uint_val = dow;
     621            0 :                                         replace_type = PGTYPES_TYPE_UINT;
     622            0 :                                         break;
     623              :                                         /* The week number of the year (another definition) */
     624              :                                 case 'W':
     625            0 :                                         tm->tm_mon -= 1;
     626            0 :                                         i = strftime(q, *pstr_len, "%U", tm);
     627            0 :                                         if (i == 0)
     628            0 :                                                 return -1;
     629            0 :                                         while (*q)
     630              :                                         {
     631            0 :                                                 q++;
     632            0 :                                                 (*pstr_len)--;
     633              :                                         }
     634            0 :                                         tm->tm_mon += 1;
     635            0 :                                         replace_type = PGTYPES_TYPE_NOTHING;
     636            0 :                                         break;
     637              : 
     638              :                                         /*
     639              :                                          * The preferred date representation for the current
     640              :                                          * locale without the time.
     641              :                                          */
     642              :                                 case 'x':
     643              :                                         {
     644            0 :                                                 const char *fmt = "%x"; /* Keep compiler quiet about
     645              :                                                                                                  * 2-digit year */
     646              : 
     647            0 :                                                 tm->tm_mon -= 1;
     648            0 :                                                 i = strftime(q, *pstr_len, fmt, tm);
     649            0 :                                                 if (i == 0)
     650            0 :                                                         return -1;
     651            0 :                                                 while (*q)
     652              :                                                 {
     653            0 :                                                         q++;
     654            0 :                                                         (*pstr_len)--;
     655              :                                                 }
     656            0 :                                                 tm->tm_mon += 1;
     657            0 :                                                 replace_type = PGTYPES_TYPE_NOTHING;
     658            0 :                                         }
     659            0 :                                         break;
     660              : 
     661              :                                         /*
     662              :                                          * The preferred time representation for the current
     663              :                                          * locale without the date.
     664              :                                          */
     665              :                                 case 'X':
     666            0 :                                         tm->tm_mon -= 1;
     667            0 :                                         i = strftime(q, *pstr_len, "%X", tm);
     668            0 :                                         if (i == 0)
     669            0 :                                                 return -1;
     670            0 :                                         while (*q)
     671              :                                         {
     672            0 :                                                 q++;
     673            0 :                                                 (*pstr_len)--;
     674              :                                         }
     675            0 :                                         tm->tm_mon += 1;
     676            0 :                                         replace_type = PGTYPES_TYPE_NOTHING;
     677            0 :                                         break;
     678              :                                         /* The year without the century (2 digits, leading zeroes) */
     679              :                                 case 'y':
     680            0 :                                         replace_val.uint_val = tm->tm_year % 100;
     681            0 :                                         replace_type = PGTYPES_TYPE_UINT_2_LZ;
     682            0 :                                         break;
     683              :                                         /* The year with the century (4 digits) */
     684              :                                 case 'Y':
     685            0 :                                         replace_val.uint_val = tm->tm_year;
     686            0 :                                         replace_type = PGTYPES_TYPE_UINT;
     687            0 :                                         break;
     688              :                                         /* The time zone offset from GMT */
     689              :                                 case 'z':
     690            0 :                                         tm->tm_mon -= 1;
     691            0 :                                         i = strftime(q, *pstr_len, "%z", tm);
     692            0 :                                         if (i == 0)
     693            0 :                                                 return -1;
     694            0 :                                         while (*q)
     695              :                                         {
     696            0 :                                                 q++;
     697            0 :                                                 (*pstr_len)--;
     698              :                                         }
     699            0 :                                         tm->tm_mon += 1;
     700            0 :                                         replace_type = PGTYPES_TYPE_NOTHING;
     701            0 :                                         break;
     702              :                                         /* The name or abbreviation of the time zone */
     703              :                                 case 'Z':
     704            0 :                                         tm->tm_mon -= 1;
     705            0 :                                         i = strftime(q, *pstr_len, "%Z", tm);
     706            0 :                                         if (i == 0)
     707            0 :                                                 return -1;
     708            0 :                                         while (*q)
     709              :                                         {
     710            0 :                                                 q++;
     711            0 :                                                 (*pstr_len)--;
     712              :                                         }
     713            0 :                                         tm->tm_mon += 1;
     714            0 :                                         replace_type = PGTYPES_TYPE_NOTHING;
     715            0 :                                         break;
     716              :                                         /* A % sign */
     717              :                                 case '%':
     718            0 :                                         replace_val.char_val = '%';
     719            0 :                                         replace_type = PGTYPES_TYPE_CHAR;
     720            0 :                                         break;
     721              :                                 case '\0':
     722              :                                         /* fmtstr: foo%' - The string ends with a % sign */
     723              : 
     724              :                                         /*
     725              :                                          * this is not compliant to the specification
     726              :                                          */
     727            0 :                                         return -1;
     728              :                                 default:
     729              : 
     730              :                                         /*
     731              :                                          * if we don't know the pattern, we just copy it
     732              :                                          */
     733            0 :                                         if (*pstr_len > 1)
     734              :                                         {
     735            0 :                                                 *q = '%';
     736            0 :                                                 q++;
     737            0 :                                                 (*pstr_len)--;
     738            0 :                                                 if (*pstr_len > 1)
     739              :                                                 {
     740            0 :                                                         *q = *p;
     741            0 :                                                         q++;
     742            0 :                                                         (*pstr_len)--;
     743            0 :                                                 }
     744              :                                                 else
     745              :                                                 {
     746            0 :                                                         *q = '\0';
     747            0 :                                                         return -1;
     748              :                                                 }
     749            0 :                                                 *q = '\0';
     750            0 :                                         }
     751              :                                         else
     752            0 :                                                 return -1;
     753            0 :                                         break;
     754              :                         }
     755            0 :                         i = pgtypes_fmt_replace(replace_val, replace_type, &q, pstr_len);
     756            0 :                         if (i)
     757            0 :                                 return i;
     758            0 :                 }
     759              :                 else
     760              :                 {
     761            0 :                         if (*pstr_len > 1)
     762              :                         {
     763            0 :                                 *q = *p;
     764            0 :                                 (*pstr_len)--;
     765            0 :                                 q++;
     766            0 :                                 *q = '\0';
     767            0 :                         }
     768              :                         else
     769            0 :                                 return -1;
     770              :                 }
     771            0 :                 p++;
     772              :         }
     773            0 :         return 0;
     774            0 : }
     775              : 
     776              : 
     777              : int
     778            0 : PGTYPEStimestamp_fmt_asc(timestamp * ts, char *output, int str_len, const char *fmtstr)
     779              : {
     780            0 :         struct tm       tm;
     781            0 :         fsec_t          fsec;
     782            0 :         date            dDate;
     783            0 :         int                     dow;
     784              : 
     785            0 :         dDate = PGTYPESdate_from_timestamp(*ts);
     786            0 :         dow = PGTYPESdate_dayofweek(dDate);
     787            0 :         timestamp2tm(*ts, NULL, &tm, &fsec, NULL);
     788              : 
     789            0 :         return dttofmtasc_replace(ts, dDate, dow, &tm, output, &str_len, fmtstr);
     790            0 : }
     791              : 
     792              : int
     793            0 : PGTYPEStimestamp_sub(timestamp * ts1, timestamp * ts2, interval * iv)
     794              : {
     795            0 :         if (TIMESTAMP_NOT_FINITE(*ts1) || TIMESTAMP_NOT_FINITE(*ts2))
     796            0 :                 return PGTYPES_TS_ERR_EINFTIME;
     797              :         else
     798            0 :                 iv->time = (*ts1 - *ts2);
     799              : 
     800            0 :         iv->month = 0;
     801              : 
     802            0 :         return 0;
     803            0 : }
     804              : 
     805              : int
     806            0 : PGTYPEStimestamp_defmt_asc(const char *str, const char *fmt, timestamp * d)
     807              : {
     808            0 :         int                     year,
     809              :                                 month,
     810              :                                 day;
     811            0 :         int                     hour,
     812              :                                 minute,
     813              :                                 second;
     814            0 :         int                     tz;
     815              : 
     816            0 :         int                     i;
     817            0 :         char       *mstr;
     818            0 :         char       *mfmt;
     819              : 
     820            0 :         if (!fmt)
     821            0 :                 fmt = "%Y-%m-%d %H:%M:%S";
     822            0 :         if (!fmt[0])
     823            0 :                 return 1;
     824              : 
     825            0 :         mstr = pgtypes_strdup(str);
     826            0 :         mfmt = pgtypes_strdup(fmt);
     827              : 
     828              :         /*
     829              :          * initialize with impossible values so that we can see if the fields
     830              :          * where specified at all
     831              :          */
     832              :         /* XXX ambiguity with 1 BC for year? */
     833            0 :         year = -1;
     834            0 :         month = -1;
     835            0 :         day = -1;
     836            0 :         hour = 0;
     837            0 :         minute = -1;
     838            0 :         second = -1;
     839            0 :         tz = 0;
     840              : 
     841            0 :         i = PGTYPEStimestamp_defmt_scan(&mstr, mfmt, d, &year, &month, &day, &hour, &minute, &second, &tz);
     842            0 :         free(mstr);
     843            0 :         free(mfmt);
     844            0 :         return i;
     845            0 : }
     846              : 
     847              : /*
     848              : * add an interval to a time stamp
     849              : *
     850              : *       *tout = tin + span
     851              : *
     852              : *        returns 0 if successful
     853              : *        returns -1 if it fails
     854              : *
     855              : */
     856              : 
     857              : int
     858            0 : PGTYPEStimestamp_add_interval(timestamp * tin, interval * span, timestamp * tout)
     859              : {
     860            0 :         if (TIMESTAMP_NOT_FINITE(*tin))
     861            0 :                 *tout = *tin;
     862              :         else
     863              :         {
     864            0 :                 if (span->month != 0)
     865              :                 {
     866            0 :                         struct tm       tt,
     867            0 :                                            *tm = &tt;
     868            0 :                         fsec_t          fsec;
     869              : 
     870            0 :                         if (timestamp2tm(*tin, NULL, tm, &fsec, NULL) != 0)
     871            0 :                                 return -1;
     872            0 :                         tm->tm_mon += span->month;
     873            0 :                         if (tm->tm_mon > MONTHS_PER_YEAR)
     874              :                         {
     875            0 :                                 tm->tm_year += (tm->tm_mon - 1) / MONTHS_PER_YEAR;
     876            0 :                                 tm->tm_mon = (tm->tm_mon - 1) % MONTHS_PER_YEAR + 1;
     877            0 :                         }
     878            0 :                         else if (tm->tm_mon < 1)
     879              :                         {
     880            0 :                                 tm->tm_year += tm->tm_mon / MONTHS_PER_YEAR - 1;
     881            0 :                                 tm->tm_mon = tm->tm_mon % MONTHS_PER_YEAR + MONTHS_PER_YEAR;
     882            0 :                         }
     883              : 
     884              : 
     885              :                         /* adjust for end of month boundary problems... */
     886            0 :                         if (tm->tm_mday > day_tab[isleap(tm->tm_year)][tm->tm_mon - 1])
     887            0 :                                 tm->tm_mday = (day_tab[isleap(tm->tm_year)][tm->tm_mon - 1]);
     888              : 
     889              : 
     890            0 :                         if (tm2timestamp(tm, fsec, NULL, tin) != 0)
     891            0 :                                 return -1;
     892            0 :                 }
     893              : 
     894            0 :                 *tin += span->time;
     895            0 :                 *tout = *tin;
     896              :         }
     897              : 
     898            0 :         return 0;
     899            0 : }
     900              : 
     901              : 
     902              : /*
     903              : * subtract an interval from a time stamp
     904              : *
     905              : *       *tout = tin - span
     906              : *
     907              : *        returns 0 if successful
     908              : *        returns -1 if it fails
     909              : *
     910              : */
     911              : 
     912              : int
     913            0 : PGTYPEStimestamp_sub_interval(timestamp * tin, interval * span, timestamp * tout)
     914              : {
     915            0 :         interval        tspan;
     916              : 
     917            0 :         tspan.month = -span->month;
     918            0 :         tspan.time = -span->time;
     919              : 
     920            0 :         return PGTYPEStimestamp_add_interval(tin, &tspan, tout);
     921            0 : }
        

Generated by: LCOV version 2.3.2-1