mirror of https://github.com/postgres/postgres
parent
999f12982e
commit
5e37f16be0
@ -0,0 +1,43 @@ |
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# Makefile for ecpg library
|
||||
#
|
||||
# Copyright (c) 1994, Regents of the University of California
|
||||
#
|
||||
# $Header: /cvsroot/pgsql/src/interfaces/ecpg/compatlib/Makefile,v 1.1 2003/03/30 13:26:09 meskes Exp $
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
subdir = src/interfaces/ecpg/pgtypeslib
|
||||
top_builddir = ../../../..
|
||||
include $(top_builddir)/src/Makefile.global |
||||
|
||||
NAME= ecpg_compat
|
||||
SO_MAJOR_VERSION= 1
|
||||
SO_MINOR_VERSION= 0.0
|
||||
|
||||
override CPPFLAGS := -O1 -g -I$(top_srcdir)/src/interfaces/ecpg/include -I$(top_srcdir)/src/include/utils $(CPPFLAGS) |
||||
|
||||
OBJS= informix.o
|
||||
|
||||
all: all-lib |
||||
|
||||
# Shared library stuff
|
||||
include $(top_srcdir)/src/Makefile.shlib |
||||
|
||||
install: all installdirs install-lib |
||||
|
||||
installdirs: |
||||
$(mkinstalldirs) $(DESTDIR)$(libdir)
|
||||
|
||||
uninstall: uninstall-lib |
||||
|
||||
clean distclean maintainer-clean: clean-lib |
||||
rm -f $(OBJS)
|
||||
|
||||
depend dep: |
||||
$(CC) -MM $(CFLAGS) *.c >depend
|
||||
|
||||
ifeq (depend,$(wildcard depend)) |
||||
include depend |
||||
endif |
@ -0,0 +1,361 @@ |
||||
#include <stdlib.h> |
||||
#include <string.h> |
||||
#include <errno.h> |
||||
|
||||
#include <ecpg_informix.h> |
||||
#include <pgtypes_error.h> |
||||
#include <pgtypes_date.h> |
||||
|
||||
/* we start with the numeric functions */ |
||||
int |
||||
decadd(Numeric *arg1, Numeric *arg2, Numeric *sum) |
||||
{ |
||||
int i = PGTYPESnumeric_add(arg1, arg2, sum); |
||||
|
||||
if (i == 0) /* No error */ |
||||
return 0; |
||||
if (errno == PGTYPES_NUM_OVERFLOW) |
||||
return -1200; |
||||
|
||||
return -1201;
|
||||
} |
||||
|
||||
int |
||||
deccmp(Numeric *arg1, Numeric *arg2) |
||||
{ |
||||
int i = PGTYPESnumeric_cmp(arg1, arg2); |
||||
|
||||
/* TODO: Need to return DECUNKNOWN instead of PGTYPES_NUM_BAD_NUMERIC */ |
||||
return (i); |
||||
} |
||||
|
||||
void |
||||
deccopy(Numeric *src, Numeric *target) |
||||
{ |
||||
PGTYPESnumeric_copy(src, target); |
||||
} |
||||
|
||||
static char * |
||||
strndup(char *str, int len) |
||||
{ |
||||
int real_len = strlen(str); |
||||
int use_len = (real_len > len) ? len : real_len; |
||||
|
||||
char *new = malloc(use_len + 1); |
||||
|
||||
if (new) |
||||
{ |
||||
memcpy(str, new, use_len); |
||||
new[use_len] = '\0'; |
||||
} |
||||
else |
||||
errno = ENOMEM; |
||||
|
||||
return new; |
||||
} |
||||
|
||||
int |
||||
deccvasc(char *cp, int len, Numeric *np) |
||||
{ |
||||
char *str = strndup(cp, len); /* Numeric_in always converts the complete string */ |
||||
int ret = 0; |
||||
|
||||
if (!str) |
||||
ret = -1201; |
||||
else |
||||
{ |
||||
np = PGTYPESnumeric_aton(str, NULL); |
||||
if (!np) |
||||
{ |
||||
switch (errno) |
||||
{ |
||||
case PGTYPES_NUM_OVERFLOW: ret = -1200; |
||||
break; |
||||
case PGTYPES_NUM_BAD_NUMERIC: ret = -1213; |
||||
break; |
||||
default: ret = -1216; |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
|
||||
return ret; |
||||
} |
||||
|
||||
int |
||||
deccvdbl(double dbl, Numeric *np) |
||||
{ |
||||
return(PGTYPESnumeric_dton(dbl, np)); |
||||
} |
||||
|
||||
int |
||||
deccvint(int in, Numeric *np) |
||||
{ |
||||
return(PGTYPESnumeric_iton(in, np)); |
||||
} |
||||
|
||||
int |
||||
deccvlong(long lng, Numeric *np) |
||||
{ |
||||
return(PGTYPESnumeric_lton(lng, np));
|
||||
} |
||||
|
||||
int |
||||
decdiv(Numeric *n1, Numeric *n2, Numeric *n3) |
||||
{ |
||||
int i = PGTYPESnumeric_div(n1, n2, n3), ret = 0; |
||||
|
||||
if (i != 0) |
||||
switch (errno) |
||||
{ |
||||
case PGTYPES_NUM_DIVIDE_ZERO: ret = -1202; |
||||
break; |
||||
case PGTYPES_NUM_OVERFLOW: ret = -1200; |
||||
break; |
||||
default: ret = -1201; |
||||
break; |
||||
} |
||||
|
||||
return ret; |
||||
} |
||||
|
||||
int
|
||||
decmul(Numeric *n1, Numeric *n2, Numeric *n3) |
||||
{ |
||||
int i = PGTYPESnumeric_mul(n1, n2, n3), ret = 0; |
||||
|
||||
if (i != 0) |
||||
switch (errno) |
||||
{ |
||||
case PGTYPES_NUM_OVERFLOW: ret = -1200; |
||||
break; |
||||
default: ret = -1201; |
||||
break; |
||||
} |
||||
|
||||
return ret; |
||||
} |
||||
|
||||
int |
||||
decsub(Numeric *n1, Numeric *n2, Numeric *n3) |
||||
{ |
||||
int i = PGTYPESnumeric_sub(n1, n2, n3), ret = 0; |
||||
|
||||
if (i != 0) |
||||
switch (errno) |
||||
{ |
||||
case PGTYPES_NUM_OVERFLOW: ret = -1200; |
||||
break; |
||||
default: ret = -1201; |
||||
break; |
||||
} |
||||
|
||||
return ret; |
||||
} |
||||
|
||||
int |
||||
dectoasc(Numeric *np, char *cp, int len, int right) |
||||
{ |
||||
char *str; |
||||
|
||||
if (right >= 0) |
||||
str = PGTYPESnumeric_ntoa(np, right); |
||||
else |
||||
str = PGTYPESnumeric_ntoa(np, 0); |
||||
|
||||
if (!str) |
||||
return -1; |
||||
|
||||
/* TODO: have to take care of len here and create exponatial notion if necessary */ |
||||
strncpy(cp, str, len); |
||||
free (str); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
int |
||||
dectodbl(Numeric *np, double *dblp) |
||||
{ |
||||
return(PGTYPESnumeric_ntod(np, dblp)); |
||||
} |
||||
|
||||
int |
||||
dectoint(Numeric *np, int *ip) |
||||
{ |
||||
int ret = PGTYPESnumeric_ntoi(np, ip); |
||||
|
||||
if (ret == PGTYPES_NUM_OVERFLOW) |
||||
ret = -1200; |
||||
|
||||
return ret; |
||||
} |
||||
|
||||
int |
||||
dectolong(Numeric *np, long *lngp)
|
||||
{ |
||||
int ret = PGTYPESnumeric_ntol(np, lngp); |
||||
|
||||
if (ret == PGTYPES_NUM_OVERFLOW) |
||||
ret = -1200; |
||||
|
||||
return ret; |
||||
} |
||||
|
||||
/* Now the date functions */ |
||||
int |
||||
rdatestr (Date d, char *str) |
||||
{ |
||||
char *tmp = PGTYPESdate_dtoa(d); |
||||
|
||||
if (!tmp) |
||||
return -1210; |
||||
|
||||
/* move to user allocated buffer */ |
||||
strcpy(tmp, str); |
||||
free(str); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
void |
||||
rtoday (Date *d) |
||||
{ |
||||
PGTYPESdate_today(d); |
||||
return; |
||||
} |
||||
|
||||
int |
||||
rjulmdy (Date d, short mdy[3]) |
||||
{ |
||||
PGTYPESdate_julmdy(d, (int *)mdy); |
||||
return 0; |
||||
} |
||||
|
||||
int |
||||
rdefmtdate (Date *d, char *fmt, char *str) |
||||
{ |
||||
/* TODO: take care of DBCENTURY environment variable */ |
||||
/* PGSQL functions allow all centuries */ |
||||
|
||||
if (PGTYPESdate_defmtdate(d, fmt, str) == 0) |
||||
return 0; |
||||
|
||||
switch (errno) |
||||
{ |
||||
case PGTYPES_DATE_ERR_ENOSHORTDATE: return -1209; |
||||
case PGTYPES_DATE_ERR_EARGS: |
||||
case PGTYPES_DATE_ERR_ENOTDMY: return -1212; |
||||
case PGTYPES_DATE_BAD_DAY: return -1204; |
||||
case PGTYPES_DATE_BAD_MONTH: return -1205; |
||||
default: return -1206;
|
||||
} |
||||
} |
||||
|
||||
int |
||||
rfmtdate (Date d, char *fmt, char *str) |
||||
{ |
||||
if (PGTYPESdate_fmtdate(d, fmt, str) == 0) |
||||
return 0; |
||||
|
||||
if (errno == ENOMEM) |
||||
return -1211; |
||||
|
||||
return -1210; |
||||
} |
||||
|
||||
int |
||||
rmdyjul (short mdy[3], Date *d) |
||||
{ |
||||
PGTYPESdate_mdyjul((int *)mdy, d); |
||||
return 0; |
||||
} |
||||
|
||||
/* And the datetime stuff */ |
||||
|
||||
void |
||||
dtcurrent (Timestamp *ts) |
||||
{ |
||||
return; |
||||
} |
||||
|
||||
int |
||||
dtcvasc (char *str, Timestamp *ts) |
||||
{ |
||||
return 0; |
||||
} |
||||
|
||||
int |
||||
dtsub (Timestamp *ts1, Timestamp *ts2, Interval *iv) |
||||
{ |
||||
return 0; |
||||
} |
||||
|
||||
int |
||||
dttoasc (Timestamp *ts, char *output) |
||||
{ |
||||
return 0; |
||||
} |
||||
|
||||
int |
||||
dttofmtasc (Timestamp *ts, char *output, int str_len, char *fmtstr) |
||||
{ |
||||
return 0; |
||||
} |
||||
|
||||
int |
||||
intoasc(Interval *i, char *str) |
||||
{ |
||||
return 0; |
||||
} |
||||
|
||||
/* And finally some misc functions */ |
||||
int |
||||
rstrdate (char *str, Date *d) |
||||
{ |
||||
return 0; |
||||
} |
||||
|
||||
int |
||||
rfmtlong(long lvalue, char *format, char *outbuf) |
||||
{ |
||||
return 0; |
||||
} |
||||
|
||||
int |
||||
rgetmsg(int msgnum, char *s, int maxsize) |
||||
{ |
||||
return 0; |
||||
} |
||||
|
||||
int |
||||
risnull(int vtype, char *pcvar) |
||||
{ |
||||
return 0; |
||||
} |
||||
|
||||
int |
||||
rsetnull(int vtype, char *pcvar) |
||||
{ |
||||
return 0; |
||||
} |
||||
|
||||
int |
||||
rtypalign(int offset, int type) |
||||
{ |
||||
return 0; |
||||
} |
||||
|
||||
int |
||||
rtypmsize(int type, int len) |
||||
{ |
||||
return 0; |
||||
} |
||||
|
||||
void |
||||
rupshift(char *s) |
||||
{ |
||||
return; |
||||
} |
||||
|
||||
|
||||
|
@ -1,44 +0,0 @@ |
||||
int |
||||
rfmtlong(long lvalue, char *format, char *outbuf) |
||||
{ |
||||
return 0; |
||||
} |
||||
|
||||
int |
||||
rgetmsg(int msgnum, char *s, int maxsize) |
||||
{ |
||||
return 0; |
||||
} |
||||
|
||||
int |
||||
risnull(int vtype, char *pcvar) |
||||
{ |
||||
return 0; |
||||
} |
||||
|
||||
int |
||||
rsetnull(int vtype, char *pcvar) |
||||
{ |
||||
return 0; |
||||
} |
||||
|
||||
int |
||||
rtypalign(int offset, int type) |
||||
{ |
||||
return 0; |
||||
} |
||||
|
||||
int |
||||
rtypmsize(int type, mint len) |
||||
{ |
||||
return 0; |
||||
} |
||||
|
||||
void |
||||
rupshift(char *s) |
||||
{ |
||||
return; |
||||
} |
||||
|
||||
|
||||
|
@ -0,0 +1,834 @@ |
||||
#include <math.h> |
||||
#include <time.h> |
||||
#include <string.h> |
||||
#include <errno.h> |
||||
#include <float.h> |
||||
#include <stdio.h> |
||||
#include <stdlib.h> |
||||
|
||||
#ifdef __FAST_MATH__ |
||||
#error -ffast-math is known to break this code |
||||
#endif |
||||
|
||||
#include "dt.h" |
||||
#include "extern.h" |
||||
#include "pgtypes_error.h" |
||||
#include "pgtypes_interval.h" |
||||
#include "datetime.h" |
||||
|
||||
/* TrimTrailingZeros()
|
||||
* ... resulting from printing numbers with full precision. |
||||
*/ |
||||
static void |
||||
TrimTrailingZeros(char *str) |
||||
{ |
||||
int len = strlen(str); |
||||
|
||||
/* chop off trailing zeros... but leave at least 2 fractional digits */ |
||||
while ((*(str + len - 1) == '0') |
||||
&& (*(str + len - 3) != '.')) |
||||
{ |
||||
len--; |
||||
*(str + len) = '\0'; |
||||
} |
||||
} |
||||
|
||||
/* DecodeTime()
|
||||
* Decode time string which includes delimiters. |
||||
* Only check the lower limit on hours, since this same code |
||||
* can be used to represent time spans. |
||||
*/ |
||||
static int |
||||
DecodeTime(char *str, int fmask, int *tmask, struct tm * tm, fsec_t *fsec) |
||||
{ |
||||
char *cp; |
||||
|
||||
*tmask = DTK_TIME_M; |
||||
|
||||
tm->tm_hour = strtol(str, &cp, 10); |
||||
if (*cp != ':') |
||||
return -1; |
||||
str = cp + 1; |
||||
tm->tm_min = strtol(str, &cp, 10); |
||||
if (*cp == '\0') |
||||
{ |
||||
tm->tm_sec = 0; |
||||
*fsec = 0; |
||||
} |
||||
else if (*cp != ':') |
||||
return -1; |
||||
else |
||||
{ |
||||
str = cp + 1; |
||||
tm->tm_sec = strtol(str, &cp, 10); |
||||
if (*cp == '\0') |
||||
*fsec = 0; |
||||
else if (*cp == '.') |
||||
{ |
||||
#ifdef HAVE_INT64_TIMESTAMP |
||||
char fstr[MAXDATELEN + 1]; |
||||
|
||||
/*
|
||||
* OK, we have at most six digits to work with. Let's |
||||
* construct a string and then do the conversion to an |
||||
* integer. |
||||
*/ |
||||
strncpy(fstr, (cp + 1), 7); |
||||
strcpy((fstr + strlen(fstr)), "000000"); |
||||
*(fstr + 6) = '\0'; |
||||
*fsec = strtol(fstr, &cp, 10); |
||||
#else |
||||
str = cp; |
||||
*fsec = strtod(str, &cp); |
||||
#endif |
||||
if (*cp != '\0') |
||||
return -1; |
||||
} |
||||
else |
||||
return -1; |
||||
} |
||||
|
||||
/* do a sanity check */ |
||||
#ifdef HAVE_INT64_TIMESTAMP |
||||
if ((tm->tm_hour < 0) |
||||
|| (tm->tm_min < 0) || (tm->tm_min > 59) |
||||
|| (tm->tm_sec < 0) || (tm->tm_sec > 59) |
||||
|| (*fsec >= INT64CONST(1000000))) |
||||
return -1; |
||||
#else |
||||
if ((tm->tm_hour < 0) |
||||
|| (tm->tm_min < 0) || (tm->tm_min > 59) |
||||
|| (tm->tm_sec < 0) || (tm->tm_sec > 59) |
||||
|| (*fsec >= 1)) |
||||
return -1; |
||||
#endif |
||||
|
||||
return 0; |
||||
} /* DecodeTime() */ |
||||
|
||||
/* DecodeInterval()
|
||||
* Interpret previously parsed fields for general time interval. |
||||
* Return 0 if decoded and -1 if problems. |
||||
* |
||||
* Allow "date" field DTK_DATE since this could be just |
||||
* an unsigned floating point number. - thomas 1997-11-16 |
||||
* |
||||
* Allow ISO-style time span, with implicit units on number of days |
||||
* preceding an hh:mm:ss field. - thomas 1998-04-30 |
||||
*/ |
||||
int |
||||
DecodeInterval(char **field, int *ftype, int nf, int *dtype, struct tm * tm, fsec_t *fsec) |
||||
{ |
||||
int is_before = FALSE; |
||||
|
||||
char *cp; |
||||
int fmask = 0, |
||||
tmask, |
||||
type; |
||||
int i; |
||||
int val; |
||||
double fval; |
||||
|
||||
*dtype = DTK_DELTA; |
||||
|
||||
type = IGNORE_DTF; |
||||
tm->tm_year = 0; |
||||
tm->tm_mon = 0; |
||||
tm->tm_mday = 0; |
||||
tm->tm_hour = 0; |
||||
tm->tm_min = 0; |
||||
tm->tm_sec = 0; |
||||
*fsec = 0; |
||||
|
||||
/* read through list backwards to pick up units before values */ |
||||
for (i = nf - 1; i >= 0; i--) |
||||
{ |
||||
switch (ftype[i]) |
||||
{ |
||||
case DTK_TIME: |
||||
if (DecodeTime(field[i], fmask, &tmask, tm, fsec) != 0) |
||||
return -1; |
||||
type = DTK_DAY; |
||||
break; |
||||
|
||||
case DTK_TZ: |
||||
|
||||
/*
|
||||
* Timezone is a token with a leading sign character and |
||||
* otherwise the same as a non-signed time field |
||||
*/ |
||||
|
||||
/*
|
||||
* A single signed number ends up here, but will be |
||||
* rejected by DecodeTime(). So, work this out to drop |
||||
* through to DTK_NUMBER, which *can* tolerate this. |
||||
*/ |
||||
cp = field[i] + 1; |
||||
while ((*cp != '\0') && (*cp != ':') && (*cp != '.')) |
||||
cp++; |
||||
if ((*cp == ':') |
||||
&& (DecodeTime((field[i] + 1), fmask, &tmask, tm, fsec) == 0)) |
||||
{ |
||||
if (*field[i] == '-') |
||||
{ |
||||
/* flip the sign on all fields */ |
||||
tm->tm_hour = -tm->tm_hour; |
||||
tm->tm_min = -tm->tm_min; |
||||
tm->tm_sec = -tm->tm_sec; |
||||
*fsec = -(*fsec); |
||||
} |
||||
|
||||
/*
|
||||
* Set the next type to be a day, if units are not |
||||
* specified. This handles the case of '1 +02:03' |
||||
* since we are reading right to left. |
||||
*/ |
||||
type = DTK_DAY; |
||||
tmask = DTK_M(TZ); |
||||
break; |
||||
} |
||||
else if (type == IGNORE_DTF) |
||||
{ |
||||
if (*cp == '.') |
||||
{ |
||||
/*
|
||||
* Got a decimal point? Then assume some sort of |
||||
* seconds specification |
||||
*/ |
||||
type = DTK_SECOND; |
||||
} |
||||
else if (*cp == '\0') |
||||
{ |
||||
/*
|
||||
* Only a signed integer? Then must assume a |
||||
* timezone-like usage |
||||
*/ |
||||
type = DTK_HOUR; |
||||
} |
||||
} |
||||
/* DROP THROUGH */ |
||||
|
||||
case DTK_DATE: |
||||
case DTK_NUMBER: |
||||
val = strtol(field[i], &cp, 10); |
||||
|
||||
if (type == IGNORE_DTF) |
||||
type = DTK_SECOND; |
||||
|
||||
if (*cp == '.') |
||||
{ |
||||
fval = strtod(cp, &cp); |
||||
if (*cp != '\0') |
||||
return -1; |
||||
|
||||
if (val < 0) |
||||
fval = -(fval); |
||||
} |
||||
else if (*cp == '\0') |
||||
fval = 0; |
||||
else |
||||
return -1; |
||||
|
||||
tmask = 0; /* DTK_M(type); */ |
||||
|
||||
switch (type) |
||||
{ |
||||
case DTK_MICROSEC: |
||||
#ifdef HAVE_INT64_TIMESTAMP |
||||
*fsec += (val + fval); |
||||
#else |
||||
*fsec += ((val + fval) * 1e-6); |
||||
#endif |
||||
break; |
||||
|
||||
case DTK_MILLISEC: |
||||
#ifdef HAVE_INT64_TIMESTAMP |
||||
*fsec += ((val + fval) * 1000); |
||||
#else |
||||
*fsec += ((val + fval) * 1e-3); |
||||
#endif |
||||
break; |
||||
|
||||
case DTK_SECOND: |
||||
tm->tm_sec += val; |
||||
#ifdef HAVE_INT64_TIMESTAMP |
||||
*fsec += (fval * 1000000); |
||||
#else |
||||
*fsec += fval; |
||||
#endif |
||||
tmask = DTK_M(SECOND); |
||||
break; |
||||
|
||||
case DTK_MINUTE: |
||||
tm->tm_min += val; |
||||
if (fval != 0) |
||||
{ |
||||
int sec; |
||||
|
||||
fval *= 60; |
||||
sec = fval; |
||||
tm->tm_sec += sec; |
||||
#ifdef HAVE_INT64_TIMESTAMP |
||||
*fsec += ((fval - sec) * 1000000); |
||||
#else |
||||
*fsec += (fval - sec); |
||||
#endif |
||||
} |
||||
tmask = DTK_M(MINUTE); |
||||
break; |
||||
|
||||
case DTK_HOUR: |
||||
tm->tm_hour += val; |
||||
if (fval != 0) |
||||
{ |
||||
int sec; |
||||
|
||||
fval *= 3600; |
||||
sec = fval; |
||||
tm->tm_sec += sec; |
||||
#ifdef HAVE_INT64_TIMESTAMP |
||||
*fsec += ((fval - sec) * 1000000); |
||||
#else |
||||
*fsec += (fval - sec); |
||||
#endif |
||||
} |
||||
tmask = DTK_M(HOUR); |
||||
break; |
||||
|
||||
case DTK_DAY: |
||||
tm->tm_mday += val; |
||||
if (fval != 0) |
||||
{ |
||||
int sec; |
||||
|
||||
fval *= 86400; |
||||
sec = fval; |
||||
tm->tm_sec += sec; |
||||
#ifdef HAVE_INT64_TIMESTAMP |
||||
*fsec += ((fval - sec) * 1000000); |
||||
#else |
||||
*fsec += (fval - sec); |
||||
#endif |
||||
} |
||||
tmask = ((fmask & DTK_M(DAY)) ? 0 : DTK_M(DAY)); |
||||
break; |
||||
|
||||
case DTK_WEEK: |
||||
tm->tm_mday += val * 7; |
||||
if (fval != 0) |
||||
{ |
||||
int sec; |
||||
|
||||
fval *= (7 * 86400); |
||||
sec = fval; |
||||
tm->tm_sec += sec; |
||||
#ifdef HAVE_INT64_TIMESTAMP |
||||
*fsec += ((fval - sec) * 1000000); |
||||
#else |
||||
*fsec += (fval - sec); |
||||
#endif |
||||
} |
||||
tmask = ((fmask & DTK_M(DAY)) ? 0 : DTK_M(DAY)); |
||||
break; |
||||
|
||||
case DTK_MONTH: |
||||
tm->tm_mon += val; |
||||
if (fval != 0) |
||||
{ |
||||
int sec; |
||||
|
||||
fval *= (30 * 86400); |
||||
sec = fval; |
||||
tm->tm_sec += sec; |
||||
#ifdef HAVE_INT64_TIMESTAMP |
||||
*fsec += ((fval - sec) * 1000000); |
||||
#else |
||||
*fsec += (fval - sec); |
||||
#endif |
||||
} |
||||
tmask = DTK_M(MONTH); |
||||
break; |
||||
|
||||
case DTK_YEAR: |
||||
tm->tm_year += val; |
||||
if (fval != 0) |
||||
tm->tm_mon += (fval * 12); |
||||
tmask = ((fmask & DTK_M(YEAR)) ? 0 : DTK_M(YEAR)); |
||||
break; |
||||
|
||||
case DTK_DECADE: |
||||
tm->tm_year += val * 10; |
||||
if (fval != 0) |
||||
tm->tm_mon += (fval * 120); |
||||
tmask = ((fmask & DTK_M(YEAR)) ? 0 : DTK_M(YEAR)); |
||||
break; |
||||
|
||||
case DTK_CENTURY: |
||||
tm->tm_year += val * 100; |
||||
if (fval != 0) |
||||
tm->tm_mon += (fval * 1200); |
||||
tmask = ((fmask & DTK_M(YEAR)) ? 0 : DTK_M(YEAR)); |
||||
break; |
||||
|
||||
case DTK_MILLENNIUM: |
||||
tm->tm_year += val * 1000; |
||||
if (fval != 0) |
||||
tm->tm_mon += (fval * 12000); |
||||
tmask = ((fmask & DTK_M(YEAR)) ? 0 : DTK_M(YEAR)); |
||||
break; |
||||
|
||||
default: |
||||
return -1; |
||||
} |
||||
break; |
||||
|
||||
case DTK_STRING: |
||||
case DTK_SPECIAL: |
||||
type = DecodeUnits(i, field[i], &val); |
||||
if (type == IGNORE_DTF) |
||||
continue; |
||||
|
||||
tmask = 0; /* DTK_M(type); */ |
||||
switch (type) |
||||
{ |
||||
case UNITS: |
||||
type = val; |
||||
break; |
||||
|
||||
case AGO: |
||||
is_before = TRUE; |
||||
type = val; |
||||
break; |
||||
|
||||
case RESERV: |
||||
tmask = (DTK_DATE_M || DTK_TIME_M); |
||||
*dtype = val; |
||||
break; |
||||
|
||||
default: |
||||
return -1; |
||||
} |
||||
break; |
||||
|
||||
default: |
||||
return -1; |
||||
} |
||||
|
||||
if (tmask & fmask) |
||||
return -1; |
||||
fmask |= tmask; |
||||
} |
||||
|
||||
if (*fsec != 0) |
||||
{ |
||||
int sec; |
||||
|
||||
#ifdef HAVE_INT64_TIMESTAMP |
||||
sec = (*fsec / INT64CONST(1000000)); |
||||
*fsec -= (sec * INT64CONST(1000000)); |
||||
#else |
||||
TMODULO(*fsec, sec, 1e0); |
||||
#endif |
||||
tm->tm_sec += sec; |
||||
} |
||||
|
||||
if (is_before) |
||||
{ |
||||
*fsec = -(*fsec); |
||||
tm->tm_sec = -(tm->tm_sec); |
||||
tm->tm_min = -(tm->tm_min); |
||||
tm->tm_hour = -(tm->tm_hour); |
||||
tm->tm_mday = -(tm->tm_mday); |
||||
tm->tm_mon = -(tm->tm_mon); |
||||
tm->tm_year = -(tm->tm_year); |
||||
} |
||||
|
||||
/* ensure that at least one time field has been found */ |
||||
return (fmask != 0) ? 0 : -1; |
||||
} /* DecodeInterval() */ |
||||
|
||||
/* EncodeInterval()
|
||||
* Interpret time structure as a delta time and convert to string. |
||||
* |
||||
* Support "traditional Postgres" and ISO-8601 styles. |
||||
* Actually, afaik ISO does not address time interval formatting, |
||||
* but this looks similar to the spec for absolute date/time. |
||||
* - thomas 1998-04-30 |
||||
*/ |
||||
int |
||||
EncodeInterval(struct tm * tm, fsec_t fsec, int style, char *str) |
||||
{ |
||||
int is_before = FALSE; |
||||
int is_nonzero = FALSE; |
||||
char *cp = str; |
||||
|
||||
/*
|
||||
* The sign of year and month are guaranteed to match, since they are |
||||
* stored internally as "month". But we'll need to check for is_before |
||||
* and is_nonzero when determining the signs of hour/minute/seconds |
||||
* fields. |
||||
*/ |
||||
switch (style) |
||||
{ |
||||
/* compatible with ISO date formats */ |
||||
case USE_ISO_DATES: |
||||
if (tm->tm_year != 0) |
||||
{ |
||||
sprintf(cp, "%d year%s", |
||||
tm->tm_year, ((tm->tm_year != 1) ? "s" : "")); |
||||
cp += strlen(cp); |
||||
is_before = (tm->tm_year < 0); |
||||
is_nonzero = TRUE; |
||||
} |
||||
|
||||
if (tm->tm_mon != 0) |
||||
{ |
||||
sprintf(cp, "%s%s%d mon%s", (is_nonzero ? " " : ""), |
||||
((is_before && (tm->tm_mon > 0)) ? "+" : ""), |
||||
tm->tm_mon, ((tm->tm_mon != 1) ? "s" : "")); |
||||
cp += strlen(cp); |
||||
is_before = (tm->tm_mon < 0); |
||||
is_nonzero = TRUE; |
||||
} |
||||
|
||||
if (tm->tm_mday != 0) |
||||
{ |
||||
sprintf(cp, "%s%s%d day%s", (is_nonzero ? " " : ""), |
||||
((is_before && (tm->tm_mday > 0)) ? "+" : ""), |
||||
tm->tm_mday, ((tm->tm_mday != 1) ? "s" : "")); |
||||
cp += strlen(cp); |
||||
is_before = (tm->tm_mday < 0); |
||||
is_nonzero = TRUE; |
||||
} |
||||
if ((!is_nonzero) || (tm->tm_hour != 0) || (tm->tm_min != 0) |
||||
|| (tm->tm_sec != 0) || (fsec != 0)) |
||||
{ |
||||
int minus = ((tm->tm_hour < 0) || (tm->tm_min < 0) |
||||
|| (tm->tm_sec < 0) || (fsec < 0)); |
||||
|
||||
sprintf(cp, "%s%s%02d:%02d", (is_nonzero ? " " : ""), |
||||
(minus ? "-" : (is_before ? "+" : "")), |
||||
abs(tm->tm_hour), abs(tm->tm_min)); |
||||
cp += strlen(cp); |
||||
/* Mark as "non-zero" since the fields are now filled in */ |
||||
is_nonzero = TRUE; |
||||
|
||||
/* fractional seconds? */ |
||||
if (fsec != 0) |
||||
{ |
||||
#ifdef HAVE_INT64_TIMESTAMP |
||||
sprintf(cp, ":%02d", abs(tm->tm_sec)); |
||||
cp += strlen(cp); |
||||
sprintf(cp, ".%06d", ((fsec >= 0) ? fsec : -(fsec))); |
||||
#else |
||||
fsec += tm->tm_sec; |
||||
sprintf(cp, ":%013.10f", fabs(fsec)); |
||||
#endif |
||||
TrimTrailingZeros(cp); |
||||
cp += strlen(cp); |
||||
is_nonzero = TRUE; |
||||
} |
||||
/* otherwise, integer seconds only? */ |
||||
else if (tm->tm_sec != 0) |
||||
{ |
||||
sprintf(cp, ":%02d", abs(tm->tm_sec)); |
||||
cp += strlen(cp); |
||||
is_nonzero = TRUE; |
||||
} |
||||
} |
||||
break; |
||||
|
||||
case USE_POSTGRES_DATES: |
||||
default: |
||||
strcpy(cp, "@ "); |
||||
cp += strlen(cp); |
||||
|
||||
if (tm->tm_year != 0) |
||||
{ |
||||
int year = tm->tm_year; |
||||
|
||||
if (tm->tm_year < 0) |
||||
year = -year; |
||||
|
||||
sprintf(cp, "%d year%s", year, |
||||
((year != 1) ? "s" : "")); |
||||
cp += strlen(cp); |
||||
is_before = (tm->tm_year < 0); |
||||
is_nonzero = TRUE; |
||||
} |
||||
|
||||
if (tm->tm_mon != 0) |
||||
{ |
||||
int mon = tm->tm_mon; |
||||
|
||||
if (is_before || ((!is_nonzero) && (tm->tm_mon < 0))) |
||||
mon = -mon; |
||||
|
||||
sprintf(cp, "%s%d mon%s", (is_nonzero ? " " : ""), mon, |
||||
((mon != 1) ? "s" : "")); |
||||
cp += strlen(cp); |
||||
if (!is_nonzero) |
||||
is_before = (tm->tm_mon < 0); |
||||
is_nonzero = TRUE; |
||||
} |
||||
|
||||
if (tm->tm_mday != 0) |
||||
{ |
||||
int day = tm->tm_mday; |
||||
|
||||
if (is_before || ((!is_nonzero) && (tm->tm_mday < 0))) |
||||
day = -day; |
||||
|
||||
sprintf(cp, "%s%d day%s", (is_nonzero ? " " : ""), day, |
||||
((day != 1) ? "s" : "")); |
||||
cp += strlen(cp); |
||||
if (!is_nonzero) |
||||
is_before = (tm->tm_mday < 0); |
||||
is_nonzero = TRUE; |
||||
} |
||||
if (tm->tm_hour != 0) |
||||
{ |
||||
int hour = tm->tm_hour; |
||||
|
||||
if (is_before || ((!is_nonzero) && (tm->tm_hour < 0))) |
||||
hour = -hour; |
||||
|
||||
sprintf(cp, "%s%d hour%s", (is_nonzero ? " " : ""), hour, |
||||
((hour != 1) ? "s" : "")); |
||||
cp += strlen(cp); |
||||
if (!is_nonzero) |
||||
is_before = (tm->tm_hour < 0); |
||||
is_nonzero = TRUE; |
||||
} |
||||
|
||||
if (tm->tm_min != 0) |
||||
{ |
||||
int min = tm->tm_min; |
||||
|
||||
if (is_before || ((!is_nonzero) && (tm->tm_min < 0))) |
||||
min = -min; |
||||
|
||||
sprintf(cp, "%s%d min%s", (is_nonzero ? " " : ""), min, |
||||
((min != 1) ? "s" : "")); |
||||
cp += strlen(cp); |
||||
if (!is_nonzero) |
||||
is_before = (tm->tm_min < 0); |
||||
is_nonzero = TRUE; |
||||
} |
||||
|
||||
/* fractional seconds? */ |
||||
if (fsec != 0) |
||||
{ |
||||
#ifdef HAVE_INT64_TIMESTAMP |
||||
if (is_before || ((!is_nonzero) && (tm->tm_sec < 0))) |
||||
tm->tm_sec = -tm->tm_sec; |
||||
sprintf(cp, "%s%d.%02d secs", (is_nonzero ? " " : ""), |
||||
tm->tm_sec, (((int) fsec) / 10000)); |
||||
cp += strlen(cp); |
||||
if (!is_nonzero) |
||||
is_before = (fsec < 0); |
||||
#else |
||||
fsec_t sec; |
||||
|
||||
fsec += tm->tm_sec; |
||||
sec = fsec; |
||||
if (is_before || ((!is_nonzero) && (fsec < 0))) |
||||
sec = -sec; |
||||
|
||||
sprintf(cp, "%s%.2f secs", (is_nonzero ? " " : ""), sec); |
||||
cp += strlen(cp); |
||||
if (!is_nonzero) |
||||
is_before = (fsec < 0); |
||||
#endif |
||||
is_nonzero = TRUE; |
||||
|
||||
/* otherwise, integer seconds only? */ |
||||
} |
||||
else if (tm->tm_sec != 0) |
||||
{ |
||||
int sec = tm->tm_sec; |
||||
|
||||
if (is_before || ((!is_nonzero) && (tm->tm_sec < 0))) |
||||
sec = -sec; |
||||
|
||||
sprintf(cp, "%s%d sec%s", (is_nonzero ? " " : ""), sec, |
||||
((sec != 1) ? "s" : "")); |
||||
cp += strlen(cp); |
||||
if (!is_nonzero) |
||||
is_before = (tm->tm_sec < 0); |
||||
is_nonzero = TRUE; |
||||
} |
||||
break; |
||||
} |
||||
|
||||
/* identically zero? then put in a unitless zero... */ |
||||
if (!is_nonzero) |
||||
{ |
||||
strcat(cp, "0"); |
||||
cp += strlen(cp); |
||||
} |
||||
|
||||
if (is_before && (style == USE_POSTGRES_DATES)) |
||||
{ |
||||
strcat(cp, " ago"); |
||||
cp += strlen(cp); |
||||
} |
||||
|
||||
return 0; |
||||
} /* EncodeInterval() */ |
||||
|
||||
/* interval2tm()
|
||||
* Convert a interval data type to a tm structure. |
||||
*/ |
||||
static int |
||||
interval2tm(Interval span, struct tm * tm, fsec_t *fsec) |
||||
{ |
||||
#ifdef HAVE_INT64_TIMESTAMP |
||||
int64 time; |
||||
|
||||
#else |
||||
double time; |
||||
#endif |
||||
|
||||
if (span.month != 0) |
||||
{ |
||||
tm->tm_year = span.month / 12; |
||||
tm->tm_mon = span.month % 12; |
||||
|
||||
} |
||||
else |
||||
{ |
||||
tm->tm_year = 0; |
||||
tm->tm_mon = 0; |
||||
} |
||||
|
||||
time = span.time; |
||||
|
||||
#ifdef HAVE_INT64_TIMESTAMP |
||||
tm->tm_mday = (time / INT64CONST(86400000000)); |
||||
time -= (tm->tm_mday * INT64CONST(86400000000)); |
||||
tm->tm_hour = (time / INT64CONST(3600000000)); |
||||
time -= (tm->tm_hour * INT64CONST(3600000000)); |
||||
tm->tm_min = (time / INT64CONST(60000000)); |
||||
time -= (tm->tm_min * INT64CONST(60000000)); |
||||
tm->tm_sec = (time / INT64CONST(1000000)); |
||||
*fsec = (time - (tm->tm_sec * INT64CONST(1000000))); |
||||
#else |
||||
TMODULO(time, tm->tm_mday, 86400e0); |
||||
TMODULO(time, tm->tm_hour, 3600e0); |
||||
TMODULO(time, tm->tm_min, 60e0); |
||||
TMODULO(time, tm->tm_sec, 1e0); |
||||
*fsec = time; |
||||
#endif |
||||
|
||||
return 0; |
||||
} /* interval2tm() */ |
||||
|
||||
static int |
||||
tm2interval(struct tm * tm, fsec_t fsec, Interval *span) |
||||
{ |
||||
span->month = ((tm->tm_year * 12) + tm->tm_mon); |
||||
#ifdef HAVE_INT64_TIMESTAMP |
||||
span->time = ((((((((tm->tm_mday * INT64CONST(24)) |
||||
+ tm->tm_hour) * INT64CONST(60)) |
||||
+ tm->tm_min) * INT64CONST(60)) |
||||
+ tm->tm_sec) * INT64CONST(1000000)) + fsec); |
||||
#else |
||||
span->time = ((((((tm->tm_mday * 24.0) |
||||
+ tm->tm_hour) * 60.0) |
||||
+ tm->tm_min) * 60.0) |
||||
+ tm->tm_sec); |
||||
span->time = JROUND(span->time + fsec); |
||||
#endif |
||||
|
||||
return 0; |
||||
} /* tm2interval() */ |
||||
|
||||
Interval * |
||||
PGTYPESinterval_atoi(char *str, char **endptr) |
||||
{ |
||||
Interval *result = NULL; |
||||
fsec_t fsec; |
||||
struct tm tt, |
||||
*tm = &tt; |
||||
int dtype; |
||||
int nf; |
||||
char *field[MAXDATEFIELDS]; |
||||
int ftype[MAXDATEFIELDS]; |
||||
char lowstr[MAXDATELEN + MAXDATEFIELDS]; |
||||
char *realptr; |
||||
char **ptr = (endptr != NULL) ? endptr : &realptr; |
||||
|
||||
tm->tm_year = 0; |
||||
tm->tm_mon = 0; |
||||
tm->tm_mday = 0; |
||||
tm->tm_hour = 0; |
||||
tm->tm_min = 0; |
||||
tm->tm_sec = 0; |
||||
fsec = 0; |
||||
|
||||
if (strlen(str) >= sizeof(lowstr)) |
||||
{ |
||||
errno = PGTYPES_INTVL_BAD_INTERVAL; |
||||
return NULL; |
||||
} |
||||
|
||||
if ((ParseDateTime(str, lowstr, field, ftype, MAXDATEFIELDS, &nf, ptr) != 0) |
||||
|| (DecodeInterval(field, ftype, nf, &dtype, tm, &fsec) != 0)) |
||||
{ |
||||
errno = PGTYPES_INTVL_BAD_INTERVAL; |
||||
return NULL; |
||||
} |
||||
|
||||
result = (Interval *) pgtypes_alloc(sizeof(Interval)); |
||||
if (!result) |
||||
return NULL; |
||||
|
||||
if (dtype != DTK_DELTA) |
||||
{ |
||||
errno = PGTYPES_INTVL_BAD_INTERVAL; |
||||
return NULL; |
||||
} |
||||
|
||||
if (tm2interval(tm, fsec, result) != 0) |
||||
{ |
||||
errno = PGTYPES_INTVL_BAD_INTERVAL; |
||||
return NULL; |
||||
} |
||||
|
||||
return result; |
||||
} |
||||
|
||||
char * |
||||
PGTYPESinterval_itoa(Interval *span) |
||||
{ |
||||
struct tm tt, |
||||
*tm = &tt; |
||||
fsec_t fsec; |
||||
char buf[MAXDATELEN + 1]; |
||||
int DateStyle=0; |
||||
|
||||
if (interval2tm(*span, tm, &fsec) != 0) |
||||
{ |
||||
errno = PGTYPES_INTVL_BAD_INTERVAL; |
||||
return NULL; |
||||
} |
||||
|
||||
if (EncodeInterval(tm, fsec, DateStyle, buf) != 0) |
||||
{ |
||||
errno = PGTYPES_INTVL_BAD_INTERVAL; |
||||
return NULL; |
||||
} |
||||
|
||||
return pgtypes_strdup(buf); |
||||
} |
||||
|
||||
int
|
||||
PGTYPESinterval_copy(Interval *intvlsrc, Interval *intrcldest) |
||||
{ |
||||
intrcldest->time = intvlsrc->time; |
||||
intrcldest->month = intvlsrc->month; |
||||
|
||||
return 0; |
||||
} |
||||
|
Loading…
Reference in new issue