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