mirror of
https://github.com/postgres/postgres.git
synced 2025-04-25 21:42:33 +03:00
Forgot two new files and one that was moved.
This commit is contained in:
parent
999f12982e
commit
5e37f16be0
43
src/interfaces/ecpg/compatlib/Makefile
Normal file
43
src/interfaces/ecpg/compatlib/Makefile
Normal file
@ -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
|
361
src/interfaces/ecpg/compatlib/informix.c
Normal file
361
src/interfaces/ecpg/compatlib/informix.c
Normal file
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
834
src/interfaces/ecpg/pgtypeslib/interval.c
Normal file
834
src/interfaces/ecpg/pgtypeslib/interval.c
Normal file
@ -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…
x
Reference in New Issue
Block a user