提交 2e6f9756 编写于 作者: M Michael Meskes

Started adding date and timestamp.

上级 26a6378e
......@@ -1360,6 +1360,10 @@ Sun Mar 16 11:28:01 CET 2003
- Started with a pgtypes library.
- Renamed lib directory to ecpglib.
- Added numerical functions to library and preprocessor.
Don Mar 20 16:53:40 CET 2003
- Added date/timestamp to library and preprocessor.
- Set ecpg version to 2.12.0.
- Set ecpg library to 3.4.2.
- Set pgtypes library to 1.0.0
......
/* $Header: /cvsroot/pgsql/src/interfaces/ecpg/ecpglib/data.c,v 1.1 2003/03/16 10:42:53 meskes Exp $ */
/* $Header: /cvsroot/pgsql/src/interfaces/ecpg/ecpglib/data.c,v 1.2 2003/03/20 15:56:50 meskes Exp $ */
#include "postgres_fe.h"
......@@ -11,6 +11,8 @@
#include "extern.h"
#include "sqlca.h"
#include "pgtypes_numeric.h"
#include "pgtypes_date.h"
#include "pgtypes_timestamp.h"
bool
ECPGget_data(const PGresult *results, int act_tuple, int act_field, int lineno,
......@@ -99,6 +101,8 @@ ECPGget_data(const PGresult *results, int act_tuple, int act_field, int lineno,
double dres;
char *scan_length;
NumericVar *nres;
Date ddres;
Timestamp tres;
case ECPGt_short:
case ECPGt_int:
......@@ -397,7 +401,51 @@ ECPGget_data(const PGresult *results, int act_tuple, int act_field, int lineno,
PGTYPESnumeric_copy(nres, (NumericVar *)(var + offset * act_tuple));
break;
case ECPGt_date:
if (pval)
{
if (isarray && *pval == '"')
ddres = PGTYPESdate_atod(pval + 1, &scan_length);
else
ddres = PGTYPESdate_atod(pval, &scan_length);
if (isarray && *scan_length == '"')
scan_length++;
if ((isarray && *scan_length != ',' && *scan_length != '}')
|| (!isarray && *scan_length != '\0')) /* Garbage left */
{
ECPGraise(lineno, ECPG_FLOAT_FORMAT, pval);
return (false);
}
*((Date *)(var + offset * act_tuple)) = ddres;
}
break;
case ECPGt_timestamp:
if (pval)
{
if (isarray && *pval == '"')
tres = PGTYPEStimestamp_atot(pval + 1, &scan_length);
else
tres = PGTYPEStimestamp_atot(pval, &scan_length);
if (isarray && *scan_length == '"')
scan_length++;
if ((isarray && *scan_length != ',' && *scan_length != '}')
|| (!isarray && *scan_length != '\0')) /* Garbage left */
{
ECPGraise(lineno, ECPG_FLOAT_FORMAT, pval);
return (false);
}
*((Timestamp *)(var + offset * act_tuple)) = tres;
}
break;
default:
ECPGraise(lineno, ECPG_UNSUPPORTED, ECPGtype_name(type));
return (false);
......
/* $Header: /cvsroot/pgsql/src/interfaces/ecpg/ecpglib/execute.c,v 1.3 2003/03/19 16:05:41 petere Exp $ */
/* $Header: /cvsroot/pgsql/src/interfaces/ecpg/ecpglib/execute.c,v 1.4 2003/03/20 15:56:50 meskes Exp $ */
/*
* The aim is to get a simpler inteface to the database routines.
......@@ -27,6 +27,8 @@
#include "sqlca.h"
#include "sql3types.h"
#include "pgtypes_numeric.h"
#include "pgtypes_date.h"
#include "pgtypes_timestamp.h"
/* variables visible to the programs */
struct sqlca sqlca =
......@@ -59,8 +61,7 @@ struct sqlca sqlca =
/* This function returns a newly malloced string that has the \
in the argument quoted with \ and the ' quoted with ' as SQL92 says.
*/
static
char *
static char *
quote_postgres(char *arg, int lineno)
{
char *res = (char *) ECPGalloc(2 * strlen(arg) + 3, lineno);
......@@ -876,6 +877,89 @@ ECPGstore_input(const struct statement * stmt, const struct variable * var,
free(str);
}
break;
case ECPGt_date:
{
char *str = NULL;
int slen;
if (var->arrsize > 1)
{
for (element = 0; element < var->arrsize; element++)
{
str = PGTYPESdate_dtoa(*(Date *)((var + var->offset * element)->value));
slen = strlen (str);
if (!(mallocedval = ECPGrealloc(mallocedval, strlen(mallocedval) + slen + 5, stmt->lineno)))
return false;
if (!element)
strcpy(mallocedval, "'{");
strncpy(mallocedval + strlen(mallocedval), str , slen + 1);
strcpy(mallocedval + strlen(mallocedval), ",");
}
strcpy(mallocedval + strlen(mallocedval) - 1, "}'");
}
else
{
str = PGTYPESdate_dtoa(*(Date *)(var->value));
slen = strlen (str);
if (!(mallocedval = ECPGalloc(slen + 1, stmt->lineno)))
return false;
strncpy(mallocedval, str , slen);
mallocedval[slen] = '\0';
}
*tobeinserted_p = mallocedval;
*malloced_p = true;
free(str);
}
break;
case ECPGt_timestamp:
{
char *str = NULL;
int slen;
if (var->arrsize > 1)
{
for (element = 0; element < var->arrsize; element++)
{
str = PGTYPEStimestamp_ttoa(*(Timestamp *)((var + var->offset * element)->value));
slen = strlen (str);
if (!(mallocedval = ECPGrealloc(mallocedval, strlen(mallocedval) + slen + 5, stmt->lineno)))
return false;
if (!element)
strcpy(mallocedval, "'{");
strncpy(mallocedval + strlen(mallocedval), str , slen + 1);
strcpy(mallocedval + strlen(mallocedval), ",");
}
strcpy(mallocedval + strlen(mallocedval) - 1, "}'");
}
else
{
str = PGTYPEStimestamp_ttoa(*(Timestamp *)(var->value));
slen = strlen (str);
if (!(mallocedval = ECPGalloc(slen + 1, stmt->lineno)))
return false;
strncpy(mallocedval, str , slen);
mallocedval[slen] = '\0';
}
*tobeinserted_p = mallocedval;
*malloced_p = true;
free(str);
}
break;
default:
/* Not implemented yet */
ECPGraise(stmt->lineno, ECPG_UNSUPPORTED, (char *) ECPGtype_name(var->type));
......
/* $Header: /cvsroot/pgsql/src/interfaces/ecpg/ecpglib/typename.c,v 1.1 2003/03/16 10:42:53 meskes Exp $ */
/* $Header: /cvsroot/pgsql/src/interfaces/ecpg/ecpglib/typename.c,v 1.2 2003/03/20 15:56:50 meskes Exp $ */
#include "postgres_fe.h"
......@@ -49,6 +49,10 @@ ECPGtype_name(enum ECPGttype typ)
return "char";
case ECPGt_numeric:
return "numeric";
case ECPGt_date:
return "date";
case ECPGt_timestamp:
return "timestamp";
default:
abort();
}
......
......@@ -2,4 +2,14 @@
#ifndef dec_t
#define dec_t NumericVar
#define CSHORTTYPE 0
#define CMONEYTYPE 0
#define CCHARTYPE 0
#define CDECIMALTYPE 0
#define CINTTYPE 0
#define CDATETYPE 0
#define CDOUBLETYPE 0
#define CLONGTYPE 0
#endif /* dec_t */
......@@ -52,7 +52,9 @@ enum ECPGttype
ECPGt_NO_INDICATOR, /* no indicator */
ECPGt_long_long, ECPGt_unsigned_long_long,
ECPGt_descriptor, /* sql descriptor, no C variable */
ECPGt_numeric
ECPGt_numeric,
ECPGt_date,
ECPGt_timestamp
};
/* descriptor items */
......
#ifndef PGTYPES_DATETIME
#define PGTYPES_DATETIME
#define Date long
extern Date PGTYPESdate_atod(char *, char **);
extern char *PGTYPESdate_dtoa(Date);
extern int PGTYPESdate_julmdy(Date, int*);
extern int PGTYPESdate_mdyjul(int*, Date *);
extern int PGTYPESdate_day(Date);
#endif /* PGTYPES_DATETIME */
......@@ -2,5 +2,7 @@
#define PGTYPES_BAD_NUMERIC 202
#define PGTYPES_DIVIDE_ZERO 203
#define PGTYPES_BAD_DATE 300
#define PGTYPES_BAD_DATE 210
#define PGTYPES_BAD_TIMESTAMP 220
#ifndef PGTYPES_TIMESTAMP
#define PGTYPES_TIMESTAMP
#ifdef HAVE_INT64_TIMESTAMP
typedef int64 Timestamp;
typedef int64 TimestampTz;
#else
typedef double Timestamp;
typedef double TimestampTz;
#endif
extern Timestamp PGTYPEStimestamp_atot(char *, char **);
extern char *PGTYPEStimestamp_ttoa(Timestamp);
#endif /* PGTYPES_TIMESTAMP */
......@@ -4,7 +4,7 @@
#
# Copyright (c) 1994, Regents of the University of California
#
# $Header: /cvsroot/pgsql/src/interfaces/ecpg/pgtypeslib/Makefile,v 1.1 2003/03/16 10:42:54 meskes Exp $
# $Header: /cvsroot/pgsql/src/interfaces/ecpg/pgtypeslib/Makefile,v 1.2 2003/03/20 15:56:50 meskes Exp $
#
#-------------------------------------------------------------------------
......@@ -18,7 +18,7 @@ SO_MINOR_VERSION= 0.0
override CPPFLAGS := -g -I$(top_srcdir)/src/interfaces/ecpg/include -I$(top_srcdir)/src/include/utils $(CPPFLAGS)
OBJS= numeric.o
OBJS= numeric.o datetime.o common.o dt_common.o timestamp.o
all: all-lib
......
#include <errno.h>
#include "extern.h"
char *
pgtypes_alloc(long size)
{
char *new = (char *) calloc(1L, size);
if (!new)
{
errno = ENOMEM;
return NULL;
}
memset(new, '\0', size);
return (new);
}
char *
pgtypes_strdup(char *str)
{
char *new = (char *) strdup(str);
if (!new)
errno = ENOMEM;
return (new);
}
#include <ctype.h>
#include <errno.h>
#include <time.h>
#include <float.h>
#include <stdlib.h>
#include <stdio.h>
#include "dt.h"
#include "extern.h"
#include "pgtypes_error.h"
#include "pgtypes_date.h"
Date
PGTYPESdate_atod(char *str, char **endptr)
{
Date dDate;
fsec_t fsec;
struct tm tt,
*tm = &tt;
int tzp;
int dtype;
int nf;
char *field[MAXDATEFIELDS];
int ftype[MAXDATEFIELDS];
char lowstr[MAXDATELEN + 1];
char *realptr;
char **ptr = (endptr != NULL) ? endptr : &realptr;
bool EuroDates = FALSE;
if (strlen(str) >= sizeof(lowstr))
{
errno = PGTYPES_BAD_DATE;
return -1;
}
if ((ParseDateTime(str, lowstr, field, ftype, MAXDATEFIELDS, &nf, ptr) != 0)
|| (DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, &tzp, EuroDates) != 0))
{
errno = PGTYPES_BAD_DATE;
return -1;
}
switch (dtype)
{
case DTK_DATE:
break;
case DTK_EPOCH:
GetEpochTime(tm);
break;
default:
errno = PGTYPES_BAD_DATE;
return -1;
}
dDate = (date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - date2j(2000, 1, 1));
return dDate;
}
char *
PGTYPESdate_dtoa(Date dDate)
{
struct tm tt, *tm = &tt;
char buf[MAXDATELEN + 1];
int DateStyle=0;
bool EuroDates = FALSE;
j2date((dDate + date2j(2000, 1, 1)), &(tm->tm_year), &(tm->tm_mon), &(tm->tm_mday));
EncodeDateOnly(tm, DateStyle, buf, EuroDates);
return pgtypes_strdup(buf);
}
int
PGTYPESdate_julmdy(Date jd, int* mdy)
{
printf("day: %d\n", mdy[0]);
printf("month: %d\n", mdy[1]);
printf("year: %d\n", mdy[2]);
j2date((int) jd, mdy+2, mdy+1, mdy+0);
return 0;
}
int
PGTYPESdate_mdyjul(int* mdy, Date *jdate)
{
/* month is mdy[0] */
/* day is mdy[1] */
/* year is mdy[2] */
printf("day: %d\n", mdy[1]);
printf("month: %d\n", mdy[0]);
printf("year: %d\n", mdy[2]);
*jdate = (Date) date2j(mdy[2], mdy[0], mdy[1]);
return 0;
}
int
PGTYPESdate_day(Date dDate)
{
return j2day(dDate);
}
#ifndef DT_H
#define DT_H
#define MAXTZLEN 10
#ifdef HAVE_INT64_TIMESTAMP
typedef int32 fsec_t;
#else
typedef double fsec_t;
#define TIME_PREC_INV 1000000.0
#define JROUND(j) (rint(((double) (j))*TIME_PREC_INV)/TIME_PREC_INV)
#endif
#ifndef bool
#define bool char
#endif /* ndef bool */
#ifndef FALSE
#define FALSE 0
#endif /* FALSE */
#ifndef TRUE
#define TRUE 1
#endif /* TRUE */
#define USE_POSTGRES_DATES 0
#define USE_ISO_DATES 1
#define USE_SQL_DATES 2
#define USE_GERMAN_DATES 3
#define DAGO "ago"
#define EPOCH "epoch"
#define INVALID "invalid"
#define EARLY "-infinity"
#define LATE "infinity"
#define NOW "now"
#define TODAY "today"
#define TOMORROW "tomorrow"
#define YESTERDAY "yesterday"
#define ZULU "zulu"
#define DMICROSEC "usecond"
#define DMILLISEC "msecond"
#define DSECOND "second"
#define DMINUTE "minute"
#define DHOUR "hour"
#define DDAY "day"
#define DWEEK "week"
#define DMONTH "month"
#define DQUARTER "quarter"
#define DYEAR "year"
#define DDECADE "decade"
#define DCENTURY "century"
#define DMILLENNIUM "millennium"
#define DA_D "ad"
#define DB_C "bc"
#define DTIMEZONE "timezone"
#define DCURRENT "current"
/*
* Fundamental time field definitions for parsing.
*
* Meridian: am, pm, or 24-hour style.
* Millennium: ad, bc
*/
#define AM 0
#define PM 1
#define HR24 2
#define AD 0
#define BC 1
/*
* Fields for time decoding.
*
* Can't have more of these than there are bits in an unsigned int
* since these are turned into bit masks during parsing and decoding.
*
* Furthermore, the values for YEAR, MONTH, DAY, HOUR, MINUTE, SECOND
* must be in the range 0..14 so that the associated bitmasks can fit
* into the left half of an INTERVAL's typmod value.
*/
#define RESERV 0
#define MONTH 1
#define YEAR 2
#define DAY 3
#define JULIAN 4
#define TZ 5
#define DTZ 6
#define DTZMOD 7
#define IGNORE_DTF 8
#define AMPM 9
#define HOUR 10
#define MINUTE 11
#define SECOND 12
#define DOY 13
#define DOW 14
#define UNITS 15
#define ADBC 16
/* these are only for relative dates */
#define AGO 17
#define ABS_BEFORE 18
#define ABS_AFTER 19
/* generic fields to help with parsing */
#define ISODATE 20
#define ISOTIME 21
/* reserved for unrecognized string values */
#define UNKNOWN_FIELD 31
/*
* Token field definitions for time parsing and decoding.
* These need to fit into the datetkn table type.
* At the moment, that means keep them within [-127,127].
* These are also used for bit masks in DecodeDateDelta()
* so actually restrict them to within [0,31] for now.
* - thomas 97/06/19
* Not all of these fields are used for masks in DecodeDateDelta
* so allow some larger than 31. - thomas 1997-11-17
*/
#define DTK_NUMBER 0
#define DTK_STRING 1
#define DTK_DATE 2
#define DTK_TIME 3
#define DTK_TZ 4
#define DTK_AGO 5
#define DTK_SPECIAL 6
#define DTK_INVALID 7
#define DTK_CURRENT 8
#define DTK_EARLY 9
#define DTK_LATE 10
#define DTK_EPOCH 11
#define DTK_NOW 12
#define DTK_YESTERDAY 13
#define DTK_TODAY 14
#define DTK_TOMORROW 15
#define DTK_ZULU 16
#define DTK_DELTA 17
#define DTK_SECOND 18
#define DTK_MINUTE 19
#define DTK_HOUR 20
#define DTK_DAY 21
#define DTK_WEEK 22
#define DTK_MONTH 23
#define DTK_QUARTER 24
#define DTK_YEAR 25
#define DTK_DECADE 26
#define DTK_CENTURY 27
#define DTK_MILLENNIUM 28
#define DTK_MILLISEC 29
#define DTK_MICROSEC 30
#define DTK_JULIAN 31
#define DTK_DOW 32
#define DTK_DOY 33
#define DTK_TZ_HOUR 34
#define DTK_TZ_MINUTE 35
/*
* Bit mask definitions for time parsing.
*/
#define DTK_M(t) (0x01 << (t))
#define DTK_DATE_M (DTK_M(YEAR) | DTK_M(MONTH) | DTK_M(DAY))
#define DTK_TIME_M (DTK_M(HOUR) | DTK_M(MINUTE) | DTK_M(SECOND))
#define MAXDATELEN 51 /* maximum possible length of an input
* date string (not counting tr. null) */
#define MAXDATEFIELDS 25 /* maximum possible number of fields in a
* date string */
#define TOKMAXLEN 10 /* only this many chars are stored in
* datetktbl */
/* keep this struct small; it gets used a lot */
typedef struct
{
#if defined(_AIX)
char *token;
#else
char token[TOKMAXLEN];
#endif /* _AIX */
char type;
char value; /* this may be unsigned, alas */
} datetkn;
/* TMODULO()
* Macro to replace modf(), which is broken on some platforms.
* t = input and remainder
* q = integer part
* u = divisor
*/
#ifdef HAVE_INT64_TIMESTAMP
#define TMODULO(t,q,u) \
do { \
q = (t / u); \
if (q != 0) t -= (q * u); \
} while(0)
#else
#define TMODULO(t,q,u) \
do { \
q = ((t < 0)? ceil(t / u): floor(t / u)); \
if (q != 0) t -= rint(q * u); \
} while(0)
#endif
/* Global variable holding time zone information. */
#if defined(__CYGWIN__) || defined(N_PLAT_NLM)
#define TIMEZONE_GLOBAL _timezone
#else
#define TIMEZONE_GLOBAL timezone
#endif
/*
* Date/time validation
* Include check for leap year.
*/
extern int day_tab[2][13];
#define isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0))
/* Julian date support for date2j() and j2date()
* Set the minimum year to one greater than the year of the first valid day
* to avoid having to check year and day both. - tgl 97/05/08
*/
#define JULIAN_MINYEAR (-4713)
#define JULIAN_MINMONTH (11)
#define JULIAN_MINDAY (24)
#define IS_VALID_JULIAN(y,m,d) (((y) > JULIAN_MINYEAR) \
|| (((y) == JULIAN_MINYEAR) && (((m) > JULIAN_MINMONTH) \
|| (((m) == JULIAN_MINMONTH) && ((d) >= JULIAN_MINDAY)))))
#define UTIME_MINYEAR (1901)
#define UTIME_MINMONTH (12)
#define UTIME_MINDAY (14)
#define UTIME_MAXYEAR (2038)
#define UTIME_MAXMONTH (01)
#define UTIME_MAXDAY (18)
#define IS_VALID_UTIME(y,m,d) ((((y) > UTIME_MINYEAR) \
|| (((y) == UTIME_MINYEAR) && (((m) > UTIME_MINMONTH) \
|| (((m) == UTIME_MINMONTH) && ((d) >= UTIME_MINDAY))))) \
&& (((y) < UTIME_MAXYEAR) \
|| (((y) == UTIME_MAXYEAR) && (((m) < UTIME_MAXMONTH) \
|| (((m) == UTIME_MAXMONTH) && ((d) <= UTIME_MAXDAY))))))
#ifdef HUGE_VAL
#define DT_NOBEGIN (-HUGE_VAL)
#define DT_NOEND (HUGE_VAL)
#else
#define DT_NOBEGIN (-DBL_MAX)
#define DT_NOEND (DBL_MAX)
#endif
#define TIMESTAMP_NOBEGIN(j) do {j = DT_NOBEGIN;} while (0)
#define TIMESTAMP_NOEND(j) do {j = DT_NOEND;} while (0)
#define TIMESTAMP_IS_NOBEGIN(j) ((j) == DT_NOBEGIN)
#define TIMESTAMP_IS_NOEND(j) ((j) == DT_NOEND)
#define TIMESTAMP_NOT_FINITE(j) (TIMESTAMP_IS_NOBEGIN(j) || TIMESTAMP_IS_NOEND(j))
extern int DecodeTimeOnly(char **field, int *ftype,
int nf, int *dtype,
struct tm * tm, fsec_t *fsec, int *tzp);
extern int DecodeInterval(char **field, int *ftype,
int nf, int *dtype,
struct tm * tm, fsec_t *fsec);
extern int EncodeTimeOnly(struct tm * tm, fsec_t fsec, int *tzp, int style, char *str);
extern int EncodeDateTime(struct tm * tm, fsec_t fsec, int *tzp, char **tzn, int style, char *str, bool);
extern int EncodeInterval(struct tm * tm, fsec_t fsec, int style, char *str);
extern int DecodeUnits(int field, char *lowtoken, int *val);
extern bool ClearDateCache(bool, bool, bool);
extern int j2day(int jd);
extern bool CheckDateTokenTables(void);
extern int EncodeDateOnly(struct tm *, int, char *, bool);
extern void GetEpochTime(struct tm *);
extern int ParseDateTime(char *, char *, char **, int *, int, int *, char **);
extern int DecodeDateTime(char **, int *, int, int *, struct tm *, fsec_t *, int *, bool);
extern void j2date(int, int *, int *, int *);
extern int date2j(int, int, int);
extern double rint(double x);
#endif /* DT_H */
此差异已折叠。
#include <string.h>
extern char *pgtypes_alloc(long);
extern char *pgtypes_strdup(char *);
......@@ -5,9 +5,9 @@
#include <math.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include "c.h"
#include "extern.h"
#include "numeric.h"
#include "pgtypes_error.h"
......@@ -25,21 +25,6 @@
#include "pgtypes_numeric.h"
static char *
pgtypes_alloc(long size)
{
char *new = (char *) calloc(1L, size);
if (!new)
{
errno = ENOMEM;
return NULL;
}
memset(new, '\0', size);
return (new);
}
#if 0
/* ----------
* apply_typmod() -
......
#include <math.h>
#include <time.h>
#include <string.h>
#include <errno.h>
#include <float.h>
#include <stdio.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_timestamp.h"
#ifdef HAVE_INT64_TIMESTAMP
static int64
time2t(const int hour, const int min, const int sec, const fsec_t fsec)
{
return ((((((hour * 60) + min) * 60) + sec) * INT64CONST(1000000)) + fsec);
} /* time2t() */
#else
static double
time2t(const int hour, const int min, const int sec, const fsec_t fsec)
{
return ((((hour * 60) + min) * 60) + sec + fsec);
} /* time2t() */
#endif
static Timestamp
dt2local(Timestamp dt, int tz)
{
#ifdef HAVE_INT64_TIMESTAMP
dt -= (tz * INT64CONST(1000000));
#else
dt -= tz;
dt = JROUND(dt);
#endif
return dt;
} /* dt2local() */
/* tm2timestamp()
* Convert a tm structure to a timestamp data type.
* Note that year is _not_ 1900-based, but is an explicit full value.
* Also, month is one-based, _not_ zero-based.
*/
static int
tm2timestamp(struct tm * tm, fsec_t fsec, int *tzp, Timestamp *result)
{
#ifdef HAVE_INT64_TIMESTAMP
int date;
int64 time;
#else
double date,
time;
#endif
/* Julian day routines are not correct for negative Julian days */
if (!IS_VALID_JULIAN(tm->tm_year, tm->tm_mon, tm->tm_mday))
return -1;
date = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - date2j(2000, 1, 1);
time = time2t(tm->tm_hour, tm->tm_min, tm->tm_sec, fsec);
#ifdef HAVE_INT64_TIMESTAMP
*result = ((date * INT64CONST(86400000000)) + time);
if ((*result < 0 && date >= 0) || (*result >= 0 && date < 0))
elog(ERROR, "TIMESTAMP out of range '%04d-%02d-%02d'",
tm->tm_year, tm->tm_mon, tm->tm_mday);
#else
*result = ((date * 86400) + time);
#endif
if (tzp != NULL)
*result = dt2local(*result, -(*tzp));
return 0;
} /* tm2timestamp() */
static Timestamp
SetEpochTimestamp(void)
{
Timestamp dt;
struct tm tt, *tm = &tt;
GetEpochTime(tm);
tm2timestamp(tm, 0, NULL, &dt);
return dt;
} /* SetEpochTimestamp() */
static void
dt2time(Timestamp jd, int *hour, int *min, int *sec, fsec_t *fsec)
{
#ifdef HAVE_INT64_TIMESTAMP
int64 time;
#else
double time;
#endif
time = jd;
#ifdef HAVE_INT64_TIMESTAMP
*hour = (time / INT64CONST(3600000000));
time -= ((*hour) * INT64CONST(3600000000));
*min = (time / INT64CONST(60000000));
time -= ((*min) * INT64CONST(60000000));
*sec = (time / INT64CONST(1000000));
*fsec = (time - (*sec * INT64CONST(1000000)));
*sec = (time / INT64CONST(1000000));
*fsec = (time - (*sec * INT64CONST(1000000)));
#else
*hour = (time / 3600);
time -= ((*hour) * 3600);
*min = (time / 60);
time -= ((*min) * 60);
*sec = time;
*fsec = JROUND(time - *sec);
#endif
return;
} /* dt2time() */
/* timestamp2tm()
* Convert timestamp data type to POSIX time structure.
* Note that year is _not_ 1900-based, but is an explicit full value.
* Also, month is one-based, _not_ zero-based.
* Returns:
* 0 on success
* -1 on out of range
*
* For dates within the system-supported time_t range, convert to the
* local time zone. If out of this range, leave as GMT. - tgl 97/05/27
*/
static int
timestamp2tm(Timestamp dt, int *tzp, struct tm * tm, fsec_t *fsec, char **tzn)
{
#ifdef HAVE_INT64_TIMESTAMP
int date,
date0;
int64 time;
#else
double date,
date0;
double time;
#endif
time_t utime;
#if defined(HAVE_TM_ZONE) || defined(HAVE_INT_TIMEZONE)
struct tm *tx;
#endif
date0 = date2j(2000, 1, 1);
time = dt;
#ifdef HAVE_INT64_TIMESTAMP
TMODULO(time, date, INT64CONST(86400000000));
if (time < INT64CONST(0))
{
time += INT64CONST(86400000000);
date -= 1;
}
#else
TMODULO(time, date, 86400e0);
if (time < 0)
{
time += 86400;
date -= 1;
}
#endif
/* Julian day routine does not work for negative Julian days */
if (date < -date0)
return -1;
/* add offset to go from J2000 back to standard Julian date */
date += date0;
j2date((int) date, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
dt2time(time, &tm->tm_hour, &tm->tm_min, &tm->tm_sec, fsec);
if (tzp != NULL)
{
/*
* Does this fall within the capabilities of the localtime()
* interface? Then use this to rotate to the local time zone.
*/
if (IS_VALID_UTIME(tm->tm_year, tm->tm_mon, tm->tm_mday))
{
#ifdef HAVE_INT64_TIMESTAMP
utime = ((dt / INT64CONST(1000000))
+ ((date0 - date2j(1970, 1, 1)) * INT64CONST(86400)));
#else
utime = (dt + ((date0 - date2j(1970, 1, 1)) * 86400));
#endif
#if defined(HAVE_TM_ZONE) || defined(HAVE_INT_TIMEZONE)
tx = localtime(&utime);
tm->tm_year = tx->tm_year + 1900;
tm->tm_mon = tx->tm_mon + 1;
tm->tm_mday = tx->tm_mday;
tm->tm_hour = tx->tm_hour;
tm->tm_min = tx->tm_min;
tm->tm_isdst = tx->tm_isdst;
#if defined(HAVE_TM_ZONE)
tm->tm_gmtoff = tx->tm_gmtoff;
tm->tm_zone = tx->tm_zone;
*tzp = -(tm->tm_gmtoff); /* tm_gmtoff is Sun/DEC-ism */
if (tzn != NULL)
*tzn = (char *) tm->tm_zone;
#elif defined(HAVE_INT_TIMEZONE)
*tzp = ((tm->tm_isdst > 0) ? (TIMEZONE_GLOBAL - 3600) : TIMEZONE_GLOBAL);
if (tzn != NULL)
*tzn = tzname[(tm->tm_isdst > 0)];
#endif
#else /* not (HAVE_TM_ZONE || HAVE_INT_TIMEZONE) */
*tzp = 0;
/* Mark this as *no* time zone available */
tm->tm_isdst = -1;
if (tzn != NULL)
*tzn = NULL;
#endif
dt = dt2local(dt, *tzp);
}
else
{
*tzp = 0;
/* Mark this as *no* time zone available */
tm->tm_isdst = -1;
if (tzn != NULL)
*tzn = NULL;
}
}
else
{
tm->tm_isdst = -1;
if (tzn != NULL)
*tzn = NULL;
}
return 0;
} /* timestamp2tm() */
/* EncodeSpecialTimestamp()
* * Convert reserved timestamp data type to string.
* */
static int
EncodeSpecialTimestamp(Timestamp dt, char *str)
{
if (TIMESTAMP_IS_NOBEGIN(dt))
strcpy(str, EARLY);
else if (TIMESTAMP_IS_NOEND(dt))
strcpy(str, LATE);
else
return FALSE;
return TRUE;
} /* EncodeSpecialTimestamp() */
Timestamp
PGTYPEStimestamp_atot(char *str, char **endptr)
{
Timestamp result;
#ifdef HAVE_INT64_TIMESTAMP
int64 noresult = 0;
#else
double noresult = 0.0;
#endif
fsec_t fsec;
struct tm tt, *tm = &tt;
int tz;
int dtype;
int nf;
char *field[MAXDATEFIELDS];
int ftype[MAXDATEFIELDS];
char lowstr[MAXDATELEN + MAXDATEFIELDS];
char *realptr;
char **ptr = (endptr != NULL) ? endptr : &realptr;
errno = 0;
if (strlen(str) >= sizeof(lowstr))
{
errno = PGTYPES_BAD_TIMESTAMP;
return (noresult);
}
if ((ParseDateTime(str, lowstr, field, ftype, MAXDATEFIELDS, &nf, ptr) != 0)
|| (DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, &tz, 0) != 0))
{
errno = PGTYPES_BAD_TIMESTAMP;
return (noresult);
}
switch (dtype)
{
case DTK_DATE:
if (tm2timestamp(tm, fsec, NULL, &result) != 0)
{
errno = PGTYPES_BAD_TIMESTAMP;
return (noresult);;
}
break;
case DTK_EPOCH:
result = SetEpochTimestamp();
break;
case DTK_LATE:
TIMESTAMP_NOEND(result);
break;
case DTK_EARLY:
TIMESTAMP_NOBEGIN(result);
break;
case DTK_INVALID:
errno = PGTYPES_BAD_TIMESTAMP;
return (noresult);
default:
errno = PGTYPES_BAD_TIMESTAMP;
return (noresult);
}
/* AdjustTimestampForTypmod(&result, typmod); */
return result;
}
char *
PGTYPEStimestamp_ttoa(Timestamp tstamp)
{
struct tm tt, *tm = &tt;
char buf[MAXDATELEN + 1];
char *tzn = NULL;
fsec_t fsec;
int DateStyle = 0;
if (TIMESTAMP_NOT_FINITE(tstamp))
EncodeSpecialTimestamp(tstamp, buf);
else if (timestamp2tm(tstamp, NULL, tm, &fsec, NULL) == 0)
EncodeDateTime(tm, fsec, NULL, &tzn, DateStyle, buf, 0);
else
{
errno = PGTYPES_BAD_TIMESTAMP;
return NULL;
}
return pgtypes_strdup(buf);
}
/* $Header: /cvsroot/pgsql/src/interfaces/ecpg/preproc/Attic/preproc.y,v 1.212 2003/03/16 10:42:54 meskes Exp $ */
/* $Header: /cvsroot/pgsql/src/interfaces/ecpg/preproc/Attic/preproc.y,v 1.213 2003/03/20 15:56:50 meskes Exp $ */
/* Copyright comment */
%{
......@@ -4223,6 +4223,22 @@ single_vt_type: common_type
$$.type_index = -1;
$$.type_sizeof = NULL;
}
else if (strcmp($1, "date") == 0)
{
$$.type_enum = ECPGt_date;
$$.type_str = make_str("Date");
$$.type_dimension = -1;
$$.type_index = -1;
$$.type_sizeof = NULL;
}
else if (strcmp($1, "timestamp") == 0)
{
$$.type_enum = ECPGt_timestamp;
$$.type_str = make_str("Timestamp");
$$.type_dimension = -1;
$$.type_index = -1;
$$.type_sizeof = NULL;
}
else
{
/* this is for typedef'ed types */
......@@ -4236,17 +4252,6 @@ single_vt_type: common_type
struct_member_list[struct_level] = ECPGstruct_member_dup(this->struct_member_list);
}
}
| ECPGColLabelCommon '(' precision opt_scale ')'
{
if (strcmp($1, "numeric") != 0 && strcmp($1, "decimal") != 0)
mmerror(PARSE_ERROR, ET_ERROR, "Only numeric/decimal have precision/scale argument");
$$.type_enum = ECPGt_numeric;
$$.type_str = EMPTY;
$$.type_dimension = -1;
$$.type_index = -1;
$$.type_sizeof = NULL;
}
;
/*
......@@ -4415,6 +4420,17 @@ common_type: simple_type
$$.type_index = -1;
$$.type_sizeof = NULL;
}
| ECPGColLabelCommon '(' precision opt_scale ')'
{
if (strcmp($1, "numeric") != 0 && strcmp($1, "decimal") != 0)
mmerror(PARSE_ERROR, ET_ERROR, "Only numeric/decimal have precision/scale argument");
$$.type_enum = ECPGt_numeric;
$$.type_str = EMPTY;
$$.type_dimension = -1;
$$.type_index = -1;
$$.type_sizeof = NULL;
}
;
var_type: common_type
......@@ -4464,6 +4480,22 @@ var_type: common_type
$$.type_index = -1;
$$.type_sizeof = NULL;
}
else if (strcmp($1, "date") == 0)
{
$$.type_enum = ECPGt_date;
$$.type_str = make_str("Date");
$$.type_dimension = -1;
$$.type_index = -1;
$$.type_sizeof = NULL;
}
else if (strcmp($1, "timestamp") == 0)
{
$$.type_enum = ECPGt_timestamp;
$$.type_str = make_str("Timestamp");
$$.type_dimension = -1;
$$.type_index = -1;
$$.type_sizeof = NULL;
}
else
{
/* this is for typedef'ed types */
......@@ -4477,17 +4509,6 @@ var_type: common_type
struct_member_list[struct_level] = ECPGstruct_member_dup(this->struct_member_list);
}
}
| ECPGColLabelCommon '(' precision opt_scale ')'
{
if (strcmp($1, "numeric") != 0 && strcmp($1, "decimal") != 0)
mmerror(PARSE_ERROR, ET_ERROR, "Only numeric/decimal have precision/scale argument");
$$.type_enum = ECPGt_numeric;
$$.type_str = EMPTY;
$$.type_dimension = -1;
$$.type_index = -1;
$$.type_sizeof = NULL;
}
;
enum_type: SQL_ENUM opt_symbol enum_definition
......
......@@ -175,6 +175,12 @@ get_type(enum ECPGttype type)
case ECPGt_descriptor:
return ("ECPGt_descriptor");
break;
case ECPGt_date:
return ("ECPGt_date");
break;
case ECPGt_timestamp:
return ("ECPGt_timestamp");
break;
default:
sprintf(errortext, "illegal variable type %d\n", type);
yyerror(errortext);
......@@ -330,6 +336,22 @@ ECPGdump_a_simple(FILE *o, const char *name, enum ECPGttype type,
sprintf(variable, "&(%s%s)", prefix ? prefix : "", name);
sprintf(offset, "sizeof(struct NumericVar)");
break;
case ECPGt_date:
/*
* we have to use a pointer and translate the variable type
*/
sprintf(variable, "&(%s%s)", prefix ? prefix : "", name);
sprintf(offset, "sizeof(Date)");
break;
case ECPGt_timestamp:
/*
* we have to use a pointer and translate the variable type
*/
sprintf(variable, "&(%s%s)", prefix ? prefix : "", name);
sprintf(offset, "sizeof(Date)");
break;
default:
/*
......
# $Header: /cvsroot/pgsql/src/interfaces/ecpg/test/Makefile,v 1.34 2003/03/16 10:42:54 meskes Exp $
# $Header: /cvsroot/pgsql/src/interfaces/ecpg/test/Makefile,v 1.35 2003/03/20 15:56:50 meskes Exp $
subdir = src/interfaces/ecpg/test
top_builddir = ../../../..
......@@ -8,7 +8,7 @@ override CPPFLAGS := -I$(srcdir)/../include $(CPPFLAGS) -g
ECPG = ../preproc/ecpg -I$(srcdir)/../include
TESTS = test1 test2 test3 test4 perftest dyntest dyntest2 test_notice test_code100 test_init testdynalloc num_test
TESTS = test1 test2 test3 test4 perftest dyntest dyntest2 test_notice test_code100 test_init testdynalloc num_test dt_test
all: $(TESTS)
......
#include <stdio.h>
#include <pgtypes_date.h>
#include <pgtypes_timestamp.h>
int
main()
{
exec sql begin declare section;
date date1;
timestamp ts1;
char *text;
exec sql end declare section;
#if 0
Date date2;
short int mdy[3] = { 4, 19, 1998 };
#endif
FILE *dbgs;
if ((dbgs = fopen("log", "w")) != NULL)
ECPGdebug(1, dbgs);
exec sql whenever sqlerror do sqlprint();
exec sql connect to mm;
exec sql create table date_test (d date, ts timestamp);
exec sql insert into date_test(d, ts) values ('Mon Jan 17 1966', '2000-7-12 17:34:29');
exec sql select * into :date1, :ts1 from date_test;
text = PGTYPESdate_dtoa(date1);
printf ("Date: %s\n", text);
ts1 = PGTYPEStimestamp_atot("2000-7-12 17:34:29", NULL);
text = PGTYPEStimestamp_ttoa(ts1);
printf ("timestamp: %s\n", text);
#if 0
PGTYPESdate_mdyjul(mdy, &date2);
printf("m: %d, d: %d, y: %d\n", mdy[0], mdy[1], mdy[2]);
/* reset */
mdy[0] = mdy[1] = mdy[2] = 0;
PGTYPESdate_julmdy(date2, mdy);
printf("m: %d, d: %d, y: %d\n", mdy[0], mdy[1], mdy[2]);
#endif
exec sql rollback;
exec sql disconnect;
if (dbgs != NULL)
fclose(dbgs);
return (0);
}
......@@ -8,6 +8,7 @@ main()
NumericVar *value1, *value2, *res;
exec sql begin declare section;
decimal(14,7) des = {0, 0, 0, 0, 0, NULL, NULL} ;
numeric num;
exec sql end declare section;
double d;
FILE *dbgs;
......@@ -52,6 +53,13 @@ main()
text = PGTYPESnumeric_ntoa(res);
PGTYPESnumeric_ntod(res, &d);
printf("div = %s %e\n", text, d);
exec sql rollback;
exec sql disconnect;
if (dbgs != NULL)
fclose(dbgs);
return (0);
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册