From 999f12982e6180a88aedc76f8e6e25f461367761 Mon Sep 17 00:00:00 2001 From: Michael Meskes Date: Sun, 30 Mar 2003 11:48:19 +0000 Subject: [PATCH] Moved Informix stuff to its own compat library. Interval datetype is now fully functional. --- src/interfaces/ecpg/ChangeLog | 10 + src/interfaces/ecpg/Makefile | 2 + src/interfaces/ecpg/ecpglib/execute.c | 10 +- src/interfaces/ecpg/include/ecpg_informix.h | 3 + src/interfaces/ecpg/include/pgtypes_date.h | 13 +- src/interfaces/ecpg/include/pgtypes_error.h | 17 +- src/interfaces/ecpg/include/pgtypes_numeric.h | 2 +- src/interfaces/ecpg/pgtypeslib/Makefile | 4 +- src/interfaces/ecpg/pgtypeslib/datetime.c | 563 ++++++++++++++++-- src/interfaces/ecpg/pgtypeslib/dt.h | 1 + src/interfaces/ecpg/pgtypeslib/dt_common.c | 106 +++- src/interfaces/ecpg/pgtypeslib/numeric.c | 223 +------ src/interfaces/ecpg/pgtypeslib/timestamp.c | 72 +-- src/interfaces/ecpg/test/dt_test.pgc | 133 ++++- 14 files changed, 810 insertions(+), 349 deletions(-) diff --git a/src/interfaces/ecpg/ChangeLog b/src/interfaces/ecpg/ChangeLog index 77ab60c2b3..321bd3a63c 100644 --- a/src/interfaces/ecpg/ChangeLog +++ b/src/interfaces/ecpg/ChangeLog @@ -1376,7 +1376,17 @@ Thu Mar 27 15:23:58 CET 2003 - Some more updates to pgtypeslib. - Set optimization to -O1 until I find the reason why code is broken with -O2. + +Sat Mar 29 22:03:16 CET 2003 + + - Moved Informix compatibility stuff its own library. + - Added interval datetypes. + +Sun Mar 30 13:43:13 CEST 2003 + + - Interval datetype now fully functional. - Set ecpg version to 2.12.0. - Set ecpg library to 3.4.2. - Set pgtypes library to 1.0.0 + - Set compat library to 1.0.0 diff --git a/src/interfaces/ecpg/Makefile b/src/interfaces/ecpg/Makefile index 50b97bc2d5..74286ce6ec 100644 --- a/src/interfaces/ecpg/Makefile +++ b/src/interfaces/ecpg/Makefile @@ -6,11 +6,13 @@ all install installdirs uninstall dep depend distprep: $(MAKE) -C include $@ $(MAKE) -C ecpglib $@ $(MAKE) -C pgtypeslib $@ + $(MAKE) -C compatlib $@ $(MAKE) -C preproc $@ clean distclean maintainer-clean: -$(MAKE) -C include $@ -$(MAKE) -C ecpglib $@ -$(MAKE) -C pgtypeslib $@ + -$(MAKE) -C compatlib $@ -$(MAKE) -C preproc $@ -$(MAKE) -C test clean diff --git a/src/interfaces/ecpg/ecpglib/execute.c b/src/interfaces/ecpg/ecpglib/execute.c index a1e0f5456b..6a9b38e7a8 100644 --- a/src/interfaces/ecpg/ecpglib/execute.c +++ b/src/interfaces/ecpg/ecpglib/execute.c @@ -1,4 +1,4 @@ -/* $Header: /cvsroot/pgsql/src/interfaces/ecpg/ecpglib/execute.c,v 1.6 2003/03/27 14:29:17 meskes Exp $ */ +/* $Header: /cvsroot/pgsql/src/interfaces/ecpg/ecpglib/execute.c,v 1.7 2003/03/30 11:48:18 meskes Exp $ */ /* * The aim is to get a simpler inteface to the database routines. @@ -847,7 +847,7 @@ ECPGstore_input(const struct statement * stmt, const struct variable * var, { for (element = 0; element < var->arrsize; element++) { - str = PGTYPESnumeric_ntoa((Numeric *)((var + var->offset * element)->value)); + str = PGTYPESnumeric_ntoa((Numeric *)((var + var->offset * element)->value), 0); slen = strlen (str); if (!(mallocedval = ECPGrealloc(mallocedval, strlen(mallocedval) + slen + 5, stmt->lineno))) @@ -863,7 +863,7 @@ ECPGstore_input(const struct statement * stmt, const struct variable * var, } else { - str = PGTYPESnumeric_ntoa((Numeric *)(var->value)); + str = PGTYPESnumeric_ntoa((Numeric *)(var->value), 0); slen = strlen (str); if (!(mallocedval = ECPGalloc(slen + 1, stmt->lineno))) @@ -1239,7 +1239,9 @@ ECPGexecute(struct statement * stmt) { ECPGlog("ECPGexecute line %d: ASYNC NOTIFY of '%s' from backend pid '%d' received\n", stmt->lineno, notify->relname, notify->be_pid); - PQfreemem(notify); +/* PQfreemem(notify);*/ + free(notify); +#warning Remove PQfreemem define } return status; diff --git a/src/interfaces/ecpg/include/ecpg_informix.h b/src/interfaces/ecpg/include/ecpg_informix.h index 3d39c90b02..46df5a2d32 100644 --- a/src/interfaces/ecpg/include/ecpg_informix.h +++ b/src/interfaces/ecpg/include/ecpg_informix.h @@ -2,6 +2,9 @@ * This file contains stuff needed to be as compatible to Informix as possible. */ +#include +#include + #define SQLNOTFOUND 100 #ifndef Date diff --git a/src/interfaces/ecpg/include/pgtypes_date.h b/src/interfaces/ecpg/include/pgtypes_date.h index 882ddab82d..76dedb866c 100644 --- a/src/interfaces/ecpg/include/pgtypes_date.h +++ b/src/interfaces/ecpg/include/pgtypes_date.h @@ -1,12 +1,17 @@ #ifndef PGTYPES_DATETIME #define PGTYPES_DATETIME +#include + #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); - +extern Date PGTYPESdate_ttod(Timestamp); +extern void PGTYPESdate_julmdy(Date, int*); +extern void PGTYPESdate_mdyjul(int*, Date *); +extern int PGTYPESdate_dayofweek(Date); +extern void PGTYPESdate_today (Date *); +extern int PGTYPESdate_defmtdate(Date *, char *, char *); +extern int PGTYPESdate_fmtdate(Date, char *, char *); #endif /* PGTYPES_DATETIME */ diff --git a/src/interfaces/ecpg/include/pgtypes_error.h b/src/interfaces/ecpg/include/pgtypes_error.h index 7cab1971b9..2965a01476 100644 --- a/src/interfaces/ecpg/include/pgtypes_error.h +++ b/src/interfaces/ecpg/include/pgtypes_error.h @@ -1,8 +1,15 @@ -#define PGTYPES_OVERFLOW 201 -#define PGTYPES_BAD_NUMERIC 202 -#define PGTYPES_DIVIDE_ZERO 203 +#define PGTYPES_NUM_OVERFLOW 201 +#define PGTYPES_NUM_BAD_NUMERIC 202 +#define PGTYPES_NUM_DIVIDE_ZERO 203 -#define PGTYPES_BAD_DATE 210 +#define PGTYPES_DATE_BAD_DATE 210 +#define PGTYPES_DATE_ERR_EARGS 211 +#define PGTYPES_DATE_ERR_ENOSHORTDATE 212 +#define PGTYPES_DATE_ERR_ENOTDMY 213 +#define PGTYPES_DATE_BAD_DAY 214 +#define PGTYPES_DATE_BAD_MONTH 215 -#define PGTYPES_BAD_TIMESTAMP 220 +#define PGTYPES_TS_BAD_TIMESTAMP 220 + +#define PGTYPES_INTVL_BAD_INTERVAL 230 diff --git a/src/interfaces/ecpg/include/pgtypes_numeric.h b/src/interfaces/ecpg/include/pgtypes_numeric.h index 3fe849a3ad..977233afca 100644 --- a/src/interfaces/ecpg/include/pgtypes_numeric.h +++ b/src/interfaces/ecpg/include/pgtypes_numeric.h @@ -23,7 +23,7 @@ typedef struct Numeric *PGTYPESnew(void); void PGTYPESnumeric_free(Numeric *); Numeric *PGTYPESnumeric_aton(char *, char **); -char *PGTYPESnumeric_ntoa(Numeric *); +char *PGTYPESnumeric_ntoa(Numeric *, int); int PGTYPESnumeric_add(Numeric *, Numeric *, Numeric *); int PGTYPESnumeric_sub(Numeric *, Numeric *, Numeric *); int PGTYPESnumeric_mul(Numeric *, Numeric *, Numeric *); diff --git a/src/interfaces/ecpg/pgtypeslib/Makefile b/src/interfaces/ecpg/pgtypeslib/Makefile index 97d8cbb24e..5a9e66408e 100644 --- a/src/interfaces/ecpg/pgtypeslib/Makefile +++ b/src/interfaces/ecpg/pgtypeslib/Makefile @@ -4,7 +4,7 @@ # # Copyright (c) 1994, Regents of the University of California # -# $Header: /cvsroot/pgsql/src/interfaces/ecpg/pgtypeslib/Makefile,v 1.3 2003/03/27 14:29:17 meskes Exp $ +# $Header: /cvsroot/pgsql/src/interfaces/ecpg/pgtypeslib/Makefile,v 1.4 2003/03/30 11:48:18 meskes Exp $ # #------------------------------------------------------------------------- @@ -18,7 +18,7 @@ SO_MINOR_VERSION= 0.0 override CPPFLAGS := -O1 -g -I$(top_srcdir)/src/interfaces/ecpg/include -I$(top_srcdir)/src/include/utils $(CPPFLAGS) -OBJS= numeric.o datetime.o common.o dt_common.o timestamp.o +OBJS= numeric.o datetime.o common.o dt_common.o timestamp.o interval.o all: all-lib diff --git a/src/interfaces/ecpg/pgtypeslib/datetime.c b/src/interfaces/ecpg/pgtypeslib/datetime.c index 4bd5c10517..fbc55462bf 100644 --- a/src/interfaces/ecpg/pgtypeslib/datetime.c +++ b/src/interfaces/ecpg/pgtypeslib/datetime.c @@ -9,7 +9,31 @@ #include "extern.h" #include "pgtypes_error.h" #include "pgtypes_date.h" -#include "ecpg_informix.h" + +/* XXX: currently not used. + * pgsql: timestamp_date() + * Convert timestamp to date data type. + */ +Date +PGTYPESdate_ttod(Timestamp dt) +{ + Date dDate; + + dDate = 0; /* suppress compiler warning */ + + if (TIMESTAMP_NOT_FINITE(dt)) + return + +#ifdef HAVE_INT64_TIMESTAMP + /* Microseconds to days */ + dDate = (dt / INT64CONST(86400000000)); +#else + /* Seconds to days */ + dDate = (dt / 86400.0); +#endif + + return dDate; +} Date PGTYPESdate_atod(char *str, char **endptr) @@ -32,14 +56,14 @@ PGTYPESdate_atod(char *str, char **endptr) if (strlen(str) >= sizeof(lowstr)) { - errno = PGTYPES_BAD_DATE; + errno = PGTYPES_DATE_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; + errno = PGTYPES_DATE_BAD_DATE; return -1; } @@ -53,7 +77,7 @@ PGTYPESdate_atod(char *str, char **endptr) break; default: - errno = PGTYPES_BAD_DATE; + errno = PGTYPES_DATE_BAD_DATE; return -1; } @@ -75,74 +99,521 @@ PGTYPESdate_dtoa(Date dDate) return pgtypes_strdup(buf); } -int +void 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 y, m, d; + + j2date((int) jd, &y, &m, &d); + mdy[0] = (short int) m; + mdy[1] = (short int) d; + mdy[2] = (short int) y; } -int +void 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) +PGTYPESdate_dayofweek(Date dDate) { - return j2day(dDate); -} - -int -rdatestr (Date d, char *str) -{ - return 0; + /* + Sunday: 0 + Monday: 1 + Tuesday: 2 + Wednesday: 3 + Thursday: 4 + Friday: 5 + Saturday: 6 + */ + return 6-j2day(dDate+3); } void -rtoday (Date *d) +PGTYPESdate_today (Date *d) { + struct tm ts; + + GetCurrentDateTime(&ts); + *d = date2j(ts.tm_year, ts.tm_mon, ts.tm_mday) - date2j(2000, 1, 1); return; } +#define PGTYPES_DATE_NUM_MAX_DIGITS 20 /* should suffice for most years... */ + +#define PGTYPES_FMTDATE_DAY_DIGITS_LZ 1 /* LZ means "leading zeroes" */ +#define PGTYPES_FMTDATE_DOW_LITERAL_SHORT 2 +#define PGTYPES_FMTDATE_MONTH_DIGITS_LZ 3 +#define PGTYPES_FMTDATE_MONTH_LITERAL_SHORT 4 +#define PGTYPES_FMTDATE_YEAR_DIGITS_SHORT 5 +#define PGTYPES_FMTDATE_YEAR_DIGITS_LONG 6 + +static char* pgtypes_date_weekdays_short[] = {"Sun", "Mon", "Tue", "Wed", + "Thu", "Fri", "Sat", NULL}; + +static char* pgtypes_date_months[] = {"January", "February", "March", "April", "May", "June", + "July", "August", "September", "October", "November", "December", NULL}; +static char* pgtypes_date_months_short[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", NULL}; + int -rjulmdy (Date d, short mdy[3]) -{ +PGTYPESdate_fmtdate(Date dDate, char* fmtstring, char* outbuf) { + static struct { + char* format; + int component; + } mapping[] = { + /* format items have to be sorted according to their length, + * since the first pattern that matches gets replaced by its + * value */ + {"ddd", PGTYPES_FMTDATE_DOW_LITERAL_SHORT }, + {"dd", PGTYPES_FMTDATE_DAY_DIGITS_LZ }, + {"mmm", PGTYPES_FMTDATE_MONTH_LITERAL_SHORT }, + {"mm", PGTYPES_FMTDATE_MONTH_DIGITS_LZ }, + {"yyyy", PGTYPES_FMTDATE_YEAR_DIGITS_LONG }, + {"yy", PGTYPES_FMTDATE_YEAR_DIGITS_SHORT }, + { NULL, 0 } + }; + + +/* These are the constants that decide which printf() format we'll use in + * order to get a string representation of the value */ +#define PGTYPES_DATE_REPLACE_STRING_MALLOCED 1 +#define PGTYPES_DATE_REPLACE_STRING_CONSTANT 2 +#define PGTYPES_DATE_REPLACE_UINT 3 +#define PGTYPES_DATE_REPLACE_UINT_2_LZ 4 +#define PGTYPES_DATE_REPLACE_UINT_4_LZ 5 + + union { + char* replace_str; + unsigned int replace_uint; + } replace_val; + int replace_type; + + int i; + int dow; + char* start_pattern; + struct tm tm; + + /* XXX error handling ? */ + /* copy the string over */ + strcpy(outbuf, fmtstring); + + /* get the date */ + j2date((dDate + date2j(2000, 1, 1)), &(tm.tm_year), &(tm.tm_mon), &(tm.tm_mday)); + dow = PGTYPESdate_dayofweek(dDate); + + for (i = 0; mapping[i].format != NULL; i++) { + while ((start_pattern = strstr(outbuf, mapping[i].format)) != NULL) { + switch(mapping[i].component) { + case PGTYPES_FMTDATE_DOW_LITERAL_SHORT: + replace_val.replace_str = pgtypes_date_weekdays_short[dow]; + replace_type = PGTYPES_DATE_REPLACE_STRING_CONSTANT; + break; + case PGTYPES_FMTDATE_DAY_DIGITS_LZ: + replace_val.replace_uint = tm.tm_mday; + replace_type = PGTYPES_DATE_REPLACE_UINT_2_LZ; + break; + case PGTYPES_FMTDATE_MONTH_LITERAL_SHORT: + replace_val.replace_str = pgtypes_date_months_short[tm.tm_mon-1]; + replace_type = PGTYPES_DATE_REPLACE_STRING_CONSTANT; + break; + case PGTYPES_FMTDATE_MONTH_DIGITS_LZ: + replace_val.replace_uint = tm.tm_mon; + replace_type = PGTYPES_DATE_REPLACE_UINT_2_LZ; + break; + case PGTYPES_FMTDATE_YEAR_DIGITS_LONG: + replace_val.replace_uint = tm.tm_year; + replace_type = PGTYPES_DATE_REPLACE_UINT_4_LZ; + break; + case PGTYPES_FMTDATE_YEAR_DIGITS_SHORT: + replace_val.replace_uint = tm.tm_year % 1000; + replace_type = PGTYPES_DATE_REPLACE_UINT_2_LZ; + break; + default: + /* should not happen, set something + * anyway */ + replace_val.replace_str = " "; + replace_type = PGTYPES_DATE_REPLACE_STRING_CONSTANT; + } + switch(replace_type) { + case PGTYPES_DATE_REPLACE_STRING_MALLOCED: + case PGTYPES_DATE_REPLACE_STRING_CONSTANT: + strncpy(start_pattern, replace_val.replace_str, + strlen(replace_val.replace_str)); + if (replace_type == PGTYPES_DATE_REPLACE_STRING_MALLOCED) { + free(replace_val.replace_str); + } + break; + case PGTYPES_DATE_REPLACE_UINT: + { + char* t = pgtypes_alloc(PGTYPES_DATE_NUM_MAX_DIGITS); + if (!t) { + return -1; + } + snprintf(t, PGTYPES_DATE_NUM_MAX_DIGITS, + "%u", replace_val.replace_uint); + strncpy(start_pattern, t, strlen(t)); + free(t); + } + break; + case PGTYPES_DATE_REPLACE_UINT_2_LZ: + { + char* t = pgtypes_alloc(PGTYPES_DATE_NUM_MAX_DIGITS); + if (!t) { + return -1; + } + snprintf(t, PGTYPES_DATE_NUM_MAX_DIGITS, + "%02u", replace_val.replace_uint); + strncpy(start_pattern, t, strlen(t)); + free(t); + } + break; + case PGTYPES_DATE_REPLACE_UINT_4_LZ: + { + char* t = pgtypes_alloc(PGTYPES_DATE_NUM_MAX_DIGITS); + if (!t) { + return -1; + } + snprintf(t, PGTYPES_DATE_NUM_MAX_DIGITS, + "%04u", replace_val.replace_uint); + strncpy(start_pattern, t, strlen(t)); + free(t); + } + break; + default: + /* doesn't happen (we set + * replace_type to + * PGTYPES_DATE_REPLACE_STRING_CONSTANT + * in case of an error above) */ + break; + } + } + } return 0; } + +/* + * PGTYPESdate_rdefmtdate + * + * function works as follows: + * - first we analyze the paramters + * - if this is a special case with no delimiters, add delimters + * - find the tokens. First we look for numerical values. If we have found + * less than 3 tokens, we check for the months' names and thereafter for + * the abbreviations of the months' names. + * - then we see which parameter should be the date, the month and the + * year and from these values we calculate the date + */ + +#define PGTYPES_DATE_MONTH_MAXLENGTH 20 /* probably even less :-) */ int -rdefmtdate (Date *d, char *fmt, char *str) +PGTYPESdate_defmtdate(Date *d, char *fmt, char *str) { + /* token[2] = { 4,6 } means that token 2 starts at + * position 4 and ends at (including) position 6 */ + int token[3][2]; + int token_values[3] = { -1, -1, -1 }; + char* fmt_token_order; + char* fmt_ystart, *fmt_mstart, *fmt_dstart; + int i; + int reading_digit; + int token_count; + char* str_copy; + struct tm tm; + + if (!d || !str || !fmt) { + errno = PGTYPES_DATE_ERR_EARGS; + return -1; + } + + /* analyze the fmt string */ + fmt_ystart = strstr(fmt, "yy"); + fmt_mstart = strstr(fmt, "mm"); + fmt_dstart = strstr(fmt, "dd"); + + if (!fmt_ystart || !fmt_mstart || !fmt_dstart) { + errno = PGTYPES_DATE_ERR_EARGS; + return -1; + } + + if (fmt_ystart < fmt_mstart) { + /* y m */ + if (fmt_dstart < fmt_ystart) { + /* d y m */ + fmt_token_order = "dym"; + } else if (fmt_dstart > fmt_mstart) { + /* y m d */ + fmt_token_order = "ymd"; + } else { + /* y d m */ + fmt_token_order = "ydm"; + } + } else { + /* fmt_ystart > fmt_mstart */ + /* m y */ + if (fmt_dstart < fmt_mstart) { + /* d m y */ + fmt_token_order = "dmy"; + } else if (fmt_dstart > fmt_ystart) { + /* m y d */ + fmt_token_order = "myd"; + } else { + /* m d y */ + fmt_token_order = "mdy"; + } + } + + /* handle the special cases where there is no delimiter between the + * digits. If we see this: + * + * only digits, 6 or 8 bytes then it might be ddmmyy and ddmmyyyy + * (or similar) + * + * we reduce it to a string with delimiters and continue processing + * */ + + /* check if we have only digits */ + reading_digit = 1; + for (i = 0; str[i]; i++) { + if (!isdigit(str[i])) { + reading_digit = 0; + break; + } + } + if (reading_digit) { + int frag_length[3]; + int target_pos; + + i = strlen(str); + if (i != 8 && i != 6) { + errno = PGTYPES_DATE_ERR_ENOSHORTDATE; + return -1; + } + /* okay, this really is the special case */ + + /* as long as the string, one additional byte for the + * terminator and 2 for the delimiters between the 3 fiedls + * */ + str_copy = pgtypes_alloc(strlen(str) + 1 + 2); + if (!str_copy) { + return -1; + } + + /* determine length of the fragments */ + if (i == 6) { + frag_length[0] = 2; frag_length[1] = 2; frag_length[2] = 2; + } else { + if (fmt_token_order[0] == 'y') { + frag_length[0] = 4; frag_length[1] = 2; frag_length[2] = 2; + } else if (fmt_token_order[1] == 'y') { + frag_length[0] = 2; frag_length[1] = 4; frag_length[2] = 2; + } else { + frag_length[0] = 2; frag_length[1] = 2; frag_length[2] = 4; + } + } + target_pos = 0; + /* XXX: Here we could calculate the positions of the tokens + * and save the for loop down there where we again check + * with isdigit() for digits. */ + for (i = 0; i < 3; i++) { + int start_pos = 0; + if (i >= 1) { start_pos += frag_length[0]; } + if (i == 2) { start_pos += frag_length[1]; } + + strncpy(str_copy + target_pos, str + start_pos, + frag_length[i]); + target_pos += frag_length[i]; + if (i != 2) { + str_copy[target_pos] = ' '; + target_pos++; + } + } + str_copy[target_pos] = '\0'; + } else { + str_copy = pgtypes_strdup(str); + if (!str_copy) { + return -1; + } + + /* convert the whole string to lower case */ + for (i = 0; str_copy[i]; i++) { + str_copy[i] = (char) tolower(str_copy[i]); + } + } + + /* look for numerical tokens */ + reading_digit = 0; + token_count = 0; + for (i = 0; i < strlen(str_copy); i++) { + if (!isdigit(str_copy[i]) && reading_digit) { + /* the token is finished */ + token[token_count][1] = i-1; + reading_digit = 0; + token_count++; + } else if (isdigit(str_copy[i]) && !reading_digit) { + /* we have found a token */ + token[token_count][0] = i; + reading_digit = 1; + } + } + /* we're at the end of the input string, but maybe we are still reading a + * number... */ + if (reading_digit) { + token[token_count][1] = i-1; + token_count++; + } + + + if (token_count < 2) { + /* not all tokens found, no way to find 2 missing tokens + * with string matches */ + free(str_copy); + errno = PGTYPES_DATE_ERR_ENOTDMY; + return -1; + } + + if (token_count != 3) { + /* not all tokens found but we may find another one with + * string matches by testing for the months names and months + * abbreviations */ + char *month_lower_tmp = pgtypes_alloc(PGTYPES_DATE_MONTH_MAXLENGTH); + char *start_pos; + int j; + int offset; + int found = 0; + char** list; + + if (!month_lower_tmp) { + /* free variables we alloc'ed before */ + free(str_copy); + return -1; + } + list = pgtypes_date_months; + for (i = 0; list[i]; i++) { + for (j = 0; j < PGTYPES_DATE_MONTH_MAXLENGTH; j++) { + month_lower_tmp[j] = (char) tolower(list[i][j]); + if (!month_lower_tmp[j]) { + /* properly terminated */ + break; + } + } + if ((start_pos = strstr(str_copy, month_lower_tmp))) { + offset = start_pos - str_copy; + /* sort the new token into the numeric + * tokens, shift them if necessary */ + if (offset < token[0][0]) { + token[2][0] = token[1][0]; + token[2][1] = token[1][1]; + token[1][0] = token[0][0]; + token[1][1] = token[0][1]; + token_count = 0; + } else if (offset < token[1][0]) { + token[2][0] = token[1][0]; + token[2][1] = token[1][1]; + token_count = 1; + } else { + token_count = 2; + } + token[token_count][0] = offset; + token[token_count][1] = offset + strlen(month_lower_tmp) - 1; + /* the value is the index of the month in + * the array of months + 1 (January is month + * 0) */ + token_values[token_count] = i+1; + found = 1; + break; + } + /* evil[tm] hack: + * if we read the pgtypes_date_months and haven't + * found a match, reset list to point to + * pgtypes_date_months_short and reset the counter + * variable i */ + if (list == pgtypes_date_months) { + if (list[i+1] == NULL) { + list = pgtypes_date_months_short; + i = -1; + } + } + } + if (!found) { + free(month_lower_tmp); + free(str_copy); + errno = PGTYPES_DATE_ERR_ENOTDMY; + return -1; + } + + /* here we found a month. token[token_count] and + * token_values[token_count] reflect the month's details. + * + * only the month can be specified with a literal. Here we can do a + * quick check if the month is at the right position according to + * the format string because we can check if the token that + * we expect to be the month is at the position of the only + * token that already has a value. If we wouldn't check here + * we could say "December 4 1990" with a fmt string of + * "dd mm yy" for 12 April 1990. + */ + if (fmt_token_order[token_count] != 'm') { + /* deal with the error later on */ + token_values[token_count] = -1; + } + free(month_lower_tmp); + } + + /* terminate the tokens with ASCII-0 and get their values */ + for (i = 0; i < 3; i++) { + *(str_copy + token[i][1] + 1) = '\0'; + /* A month already has a value set, check for token_value == -1 */ + if (token_values[i] == -1) { + errno = 0; + token_values[i] = strtol(str_copy + token[i][0], (char **) NULL, 10); + /* strtol sets errno in case of an error */ + if (errno) { + token_values[i] = -1; + } + } + if (fmt_token_order[i] == 'd') { + tm.tm_mday = token_values[i]; + } else if (fmt_token_order[i] == 'm') { + tm.tm_mon = token_values[i]; + } else if (fmt_token_order[i] == 'y') { + tm.tm_year = token_values[i]; + } + } + free(str_copy); + + if (tm.tm_mday < 1 || tm.tm_mday > 31) + { + errno = PGTYPES_DATE_BAD_DAY; + return -1; + } + + if (tm.tm_mon < 1 || tm.tm_mon > 12) + { + errno = PGTYPES_DATE_BAD_MONTH; + return -1; + } + + if (tm.tm_mday == 31 && (tm.tm_mon == 4 || tm.tm_mon == 6 || tm.tm_mon == 9 || tm.tm_mon ==11)) + { + errno = PGTYPES_DATE_BAD_DAY; + return -1; + } + + if (tm.tm_mon == 2 && tm.tm_mday > 29) + { + errno = PGTYPES_DATE_BAD_DAY; + return -1; + } + + *d = date2j(tm.tm_year, tm.tm_mon, tm.tm_mday) - date2j(2000, 1, 1); + return 0; } - -int -rfmtdate (Date d, char *fmt, char *str) -{ - return 0; -} - -int -rmdyjul (short mdy[3], Date *d) -{ - return 0; -} - -int -rstrdate (char *str, Date *d) -{ - return 0; -} - diff --git a/src/interfaces/ecpg/pgtypeslib/dt.h b/src/interfaces/ecpg/pgtypeslib/dt.h index d20c0cd819..e2019af32e 100644 --- a/src/interfaces/ecpg/pgtypeslib/dt.h +++ b/src/interfaces/ecpg/pgtypeslib/dt.h @@ -296,6 +296,7 @@ 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 void GetCurrentDateTime(struct tm*); extern int date2j(int, int, int); extern double rint(double x); diff --git a/src/interfaces/ecpg/pgtypeslib/dt_common.c b/src/interfaces/ecpg/pgtypeslib/dt_common.c index 3b85f7df15..2da16b14d4 100644 --- a/src/interfaces/ecpg/pgtypeslib/dt_common.c +++ b/src/interfaces/ecpg/pgtypeslib/dt_common.c @@ -426,10 +426,81 @@ static datetkn datetktbl[] = { {ZULU, TZ, POS(0)}, /* UTC */ }; +static datetkn deltatktbl[] = { + /* text, token, lexval */ + {"@", IGNORE_DTF, 0}, /* postgres relative prefix */ + {DAGO, AGO, 0}, /* "ago" indicates negative time offset */ + {"c", UNITS, DTK_CENTURY}, /* "century" relative */ + {"cent", UNITS, DTK_CENTURY}, /* "century" relative */ + {"centuries", UNITS, DTK_CENTURY}, /* "centuries" relative */ + {DCENTURY, UNITS, DTK_CENTURY}, /* "century" relative */ + {"d", UNITS, DTK_DAY}, /* "day" relative */ + {DDAY, UNITS, DTK_DAY}, /* "day" relative */ + {"days", UNITS, DTK_DAY}, /* "days" relative */ + {"dec", UNITS, DTK_DECADE}, /* "decade" relative */ + {DDECADE, UNITS, DTK_DECADE}, /* "decade" relative */ + {"decades", UNITS, DTK_DECADE}, /* "decades" relative */ + {"decs", UNITS, DTK_DECADE}, /* "decades" relative */ + {"h", UNITS, DTK_HOUR}, /* "hour" relative */ + {DHOUR, UNITS, DTK_HOUR}, /* "hour" relative */ + {"hours", UNITS, DTK_HOUR}, /* "hours" relative */ + {"hr", UNITS, DTK_HOUR}, /* "hour" relative */ + {"hrs", UNITS, DTK_HOUR}, /* "hours" relative */ + {INVALID, RESERV, DTK_INVALID}, /* reserved for invalid time */ + {"m", UNITS, DTK_MINUTE}, /* "minute" relative */ + {"microsecon", UNITS, DTK_MICROSEC}, /* "microsecond" relative */ + {"mil", UNITS, DTK_MILLENNIUM}, /* "millennium" relative */ + {"millennia", UNITS, DTK_MILLENNIUM}, /* "millennia" relative */ + {DMILLENNIUM, UNITS, DTK_MILLENNIUM}, /* "millennium" relative */ + {"millisecon", UNITS, DTK_MILLISEC}, /* relative */ + {"mils", UNITS, DTK_MILLENNIUM}, /* "millennia" relative */ + {"min", UNITS, DTK_MINUTE}, /* "minute" relative */ + {"mins", UNITS, DTK_MINUTE}, /* "minutes" relative */ + {DMINUTE, UNITS, DTK_MINUTE}, /* "minute" relative */ + {"minutes", UNITS, DTK_MINUTE}, /* "minutes" relative */ + {"mon", UNITS, DTK_MONTH}, /* "months" relative */ + {"mons", UNITS, DTK_MONTH}, /* "months" relative */ + {DMONTH, UNITS, DTK_MONTH}, /* "month" relative */ + {"months", UNITS, DTK_MONTH}, + {"ms", UNITS, DTK_MILLISEC}, + {"msec", UNITS, DTK_MILLISEC}, + {DMILLISEC, UNITS, DTK_MILLISEC}, + {"mseconds", UNITS, DTK_MILLISEC}, + {"msecs", UNITS, DTK_MILLISEC}, + {"qtr", UNITS, DTK_QUARTER}, /* "quarter" relative */ + {DQUARTER, UNITS, DTK_QUARTER}, /* "quarter" relative */ + {"reltime", IGNORE_DTF, 0}, /* pre-v6.1 "Undefined Reltime" */ + {"s", UNITS, DTK_SECOND}, + {"sec", UNITS, DTK_SECOND}, + {DSECOND, UNITS, DTK_SECOND}, + {"seconds", UNITS, DTK_SECOND}, + {"secs", UNITS, DTK_SECOND}, + {DTIMEZONE, UNITS, DTK_TZ}, /* "timezone" time offset */ + {"timezone_h", UNITS, DTK_TZ_HOUR}, /* timezone hour units */ + {"timezone_m", UNITS, DTK_TZ_MINUTE}, /* timezone minutes units */ + {"undefined", RESERV, DTK_INVALID}, /* pre-v6.1 invalid time */ + {"us", UNITS, DTK_MICROSEC}, /* "microsecond" relative */ + {"usec", UNITS, DTK_MICROSEC}, /* "microsecond" relative */ + {DMICROSEC, UNITS, DTK_MICROSEC}, /* "microsecond" relative */ + {"useconds", UNITS, DTK_MICROSEC}, /* "microseconds" relative */ + {"usecs", UNITS, DTK_MICROSEC}, /* "microseconds" relative */ + {"w", UNITS, DTK_WEEK}, /* "week" relative */ + {DWEEK, UNITS, DTK_WEEK}, /* "week" relative */ + {"weeks", UNITS, DTK_WEEK}, /* "weeks" relative */ + {"y", UNITS, DTK_YEAR}, /* "year" relative */ + {DYEAR, UNITS, DTK_YEAR}, /* "year" relative */ + {"years", UNITS, DTK_YEAR}, /* "years" relative */ + {"yr", UNITS, DTK_YEAR}, /* "year" relative */ + {"yrs", UNITS, DTK_YEAR}, /* "years" relative */ +}; + static unsigned int szdatetktbl = sizeof datetktbl / sizeof datetktbl[0]; +static unsigned int szdeltatktbl = sizeof deltatktbl / sizeof deltatktbl[0]; static datetkn *datecache[MAXDATEFIELDS] = {NULL}; +static datetkn *deltacache[MAXDATEFIELDS] = {NULL}; + char *months[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", NULL}; char *days[] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", NULL}; @@ -561,6 +632,39 @@ datebsearch(char *key, datetkn *base, unsigned int nel) return NULL; } +/* DecodeUnits() + * Decode text string using lookup table. + * This routine supports time interval decoding. + */ +int +DecodeUnits(int field, char *lowtoken, int *val) +{ + int type; + datetkn *tp; + + if ((deltacache[field] != NULL) + && (strncmp(lowtoken, deltacache[field]->token, TOKMAXLEN) == 0)) + tp = deltacache[field]; + else + tp = datebsearch(lowtoken, deltatktbl, szdeltatktbl); + deltacache[field] = tp; + if (tp == NULL) + { + type = UNKNOWN_FIELD; + *val = 0; + } + else + { + type = tp->type; + if ((type == TZ) || (type == DTZ)) + *val = FROMVAL(tp); + else + *val = tp->value; + } + + return type; +} /* DecodeUnits() */ + /* * Calendar time to Julian date conversions. * Julian date is commonly used in astronomical applications, @@ -1088,7 +1192,7 @@ abstime2tm(AbsoluteTime _time, int *tzp, struct tm * tm, char **tzn) #endif } -static void +void GetCurrentDateTime(struct tm * tm) { int tz; diff --git a/src/interfaces/ecpg/pgtypeslib/numeric.c b/src/interfaces/ecpg/pgtypeslib/numeric.c index 9b0a1f2e14..fc09a6e4ce 100644 --- a/src/interfaces/ecpg/pgtypeslib/numeric.c +++ b/src/interfaces/ecpg/pgtypeslib/numeric.c @@ -9,7 +9,6 @@ #include "c.h" #include "extern.h" #include "pgtypes_error.h" -#include "decimal.h" #define Max(x, y) ((x) > (y) ? (x) : (y)) #define Min(x, y) ((x) < (y) ? (x) : (y)) @@ -96,7 +95,7 @@ apply_typmod(Numeric *var, long typmod) if (tweight >= maxweight && i < var->ndigits) { - errno = PGTYPES_OVERFLOW; + errno = PGTYPES_NUM_OVERFLOW; return -1; } } @@ -188,7 +187,7 @@ set_var_from_str(char *str, char **ptr, Numeric *dest) if (!isdigit((unsigned char) *(*ptr))) { - errno=PGTYPES_BAD_NUMERIC; + errno=PGTYPES_NUM_BAD_NUMERIC; return -1; } @@ -206,7 +205,7 @@ set_var_from_str(char *str, char **ptr, Numeric *dest) { if (have_dp) { - errno = PGTYPES_BAD_NUMERIC; + errno = PGTYPES_NUM_BAD_NUMERIC; return -1; } have_dp = TRUE; @@ -227,14 +226,14 @@ set_var_from_str(char *str, char **ptr, Numeric *dest) exponent = strtol((*ptr), &endptr, 10); if (endptr == (*ptr)) { - errno = PGTYPES_BAD_NUMERIC; + errno = PGTYPES_NUM_BAD_NUMERIC; return -1; } (*ptr) = endptr; if (exponent > NUMERIC_MAX_PRECISION || exponent < -NUMERIC_MAX_PRECISION) { - errno = PGTYPES_BAD_NUMERIC; + errno = PGTYPES_NUM_BAD_NUMERIC; return -1; } dest->weight += (int) exponent; @@ -248,7 +247,7 @@ set_var_from_str(char *str, char **ptr, Numeric *dest) { if (!isspace((unsigned char) *(*ptr))) { - errno = PGTYPES_BAD_NUMERIC; + errno = PGTYPES_NUM_BAD_NUMERIC; return -1; } (*ptr)++; @@ -402,9 +401,12 @@ PGTYPESnumeric_aton(char *str, char **endptr) * ---------- */ char * -PGTYPESnumeric_ntoa(Numeric *num) +PGTYPESnumeric_ntoa(Numeric *num, int dscale) { - return(get_str_from_var(num, num->dscale)); + if (dscale <= 0) + dscale = num->dscale; + + return(get_str_from_var(num, dscale)); } /* ---------- @@ -1117,7 +1119,7 @@ PGTYPESnumeric_div(Numeric *var1, Numeric *var2, Numeric *result) ndigits_tmp = var2->ndigits + 1; if (ndigits_tmp == 1) { - errno= PGTYPES_DIVIDE_ZERO; + errno= PGTYPES_NUM_DIVIDE_ZERO; return -1; } @@ -1320,7 +1322,7 @@ PGTYPESnumeric_cmp(Numeric *var1, Numeric *var2) { return -1; } - errno = PGTYPES_BAD_NUMERIC; + errno = PGTYPES_NUM_BAD_NUMERIC; return INT_MAX; } @@ -1438,7 +1440,7 @@ numericvar_to_double_no_overflow(Numeric *var, double *dp) { /* shouldn't happen ... */ free(tmp); - errno = PGTYPES_BAD_NUMERIC; + errno = PGTYPES_NUM_BAD_NUMERIC; return -1; } *dp = val; @@ -1466,7 +1468,7 @@ PGTYPESnumeric_ntoi(Numeric* nv, int* ip) { return i; if (l < -INT_MAX || l > INT_MAX) { - errno = PGTYPES_OVERFLOW; + errno = PGTYPES_NUM_OVERFLOW; return -1; } @@ -1488,7 +1490,7 @@ PGTYPESnumeric_ntol(Numeric* nv, long* lp) { l++; } if (l > LONG_MAX || l < 0) { - errno = PGTYPES_OVERFLOW; + errno = PGTYPES_NUM_OVERFLOW; return -1; } @@ -1499,196 +1501,3 @@ PGTYPESnumeric_ntol(Numeric* nv, long* lp) { return 0; } -/* Finally we need some wrappers for the INFORMIX 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_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_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 = pgtypes_alloc(use_len + 1); - - if (new) - { - memcpy(str, new, use_len); - new[use_len] = '\0'; - } - - 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_OVERFLOW: ret = -1200; - break; - case PGTYPES_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_DIVIDE_ZERO: ret = -1202; - break; - case PGTYPES_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_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_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 = get_str_from_var(np, right); - else - str = get_str_from_var(np, np->dscale); - - 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_OVERFLOW) - ret = -1200; - - return ret; -} - -int -dectolong(Numeric *np, long *lngp) -{ - int ret = PGTYPESnumeric_ntol(np, lngp); - - if (ret == PGTYPES_OVERFLOW) - ret = -1200; - - return ret; -} - diff --git a/src/interfaces/ecpg/pgtypeslib/timestamp.c b/src/interfaces/ecpg/pgtypeslib/timestamp.c index bf1ca57c6e..181e63dc2a 100644 --- a/src/interfaces/ecpg/pgtypeslib/timestamp.c +++ b/src/interfaces/ecpg/pgtypeslib/timestamp.c @@ -13,7 +13,6 @@ #include "extern.h" #include "pgtypes_error.h" #include "pgtypes_timestamp.h" -#include "pgtypes_interval.h" #include "datetime.h" #ifdef HAVE_INT64_TIMESTAMP @@ -288,14 +287,14 @@ PGTYPEStimestamp_atot(char *str, char **endptr) errno = 0; if (strlen(str) >= sizeof(lowstr)) { - errno = PGTYPES_BAD_TIMESTAMP; + errno = PGTYPES_TS_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; + errno = PGTYPES_TS_BAD_TIMESTAMP; return (noresult); } @@ -304,7 +303,7 @@ PGTYPEStimestamp_atot(char *str, char **endptr) case DTK_DATE: if (tm2timestamp(tm, fsec, NULL, &result) != 0) { - errno = PGTYPES_BAD_TIMESTAMP; + errno = PGTYPES_TS_BAD_TIMESTAMP; return (noresult);; } break; @@ -322,11 +321,11 @@ PGTYPEStimestamp_atot(char *str, char **endptr) break; case DTK_INVALID: - errno = PGTYPES_BAD_TIMESTAMP; + errno = PGTYPES_TS_BAD_TIMESTAMP; return (noresult); default: - errno = PGTYPES_BAD_TIMESTAMP; + errno = PGTYPES_TS_BAD_TIMESTAMP; return (noresult); } @@ -350,67 +349,8 @@ PGTYPEStimestamp_ttoa(Timestamp tstamp) EncodeDateTime(tm, fsec, NULL, &tzn, DateStyle, buf, 0); else { - errno = PGTYPES_BAD_TIMESTAMP; + errno = PGTYPES_TS_BAD_TIMESTAMP; return NULL; } return pgtypes_strdup(buf); } - -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; -} - -Interval * -PGTYPESinterval_atoi(char *str, char **endptr) -{ - Interval *result = NULL; - - return result; -} - -char * -PGTYPESinterval_itoa(Interval *intvl) -{ - char buf[MAXDATELEN + 1]; - - return pgtypes_strdup(buf); -} - -int -PGTYPESinterval_copy(Interval *intvlsrc, Interval *intrcldest) -{ - return 0; -} - diff --git a/src/interfaces/ecpg/test/dt_test.pgc b/src/interfaces/ecpg/test/dt_test.pgc index 34f520f891..68d099136e 100644 --- a/src/interfaces/ecpg/test/dt_test.pgc +++ b/src/interfaces/ecpg/test/dt_test.pgc @@ -1,46 +1,153 @@ #include +#include +#include #include #include +#include int main() { exec sql begin declare section; - date date1; - timestamp ts1; - char *text; + date date1; + timestamp ts1; + interval iv1; + char *text; exec sql end declare section; -#if 0 Date date2; - short int mdy[3] = { 4, 19, 1998 }; -#endif + int mdy[3] = { 4, 19, 1998 }; + char *fmt, *out, *in; + 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 create table date_test (d date, ts timestamp, iv interval); - exec sql insert into date_test(d, ts) values ('Mon Jan 17 1966', '2000-7-12 17:34:29'); + exec sql insert into date_test(d, ts, iv) values ('Mon Jan 17 1966', '2000-7-12 17:34:29', now()-'Mon Jan 17 1966'); - exec sql select * into :date1, :ts1 from date_test; + exec sql select * into :date1, :ts1 , :iv1 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 + + text = PGTYPESinterval_itoa(&iv1); + printf ("interval: %s\n", text); + 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; + printf("date seems to get encoded to julian %ld\n", date2); + PGTYPESdate_julmdy(date2, mdy); printf("m: %d, d: %d, y: %d\n", mdy[0], mdy[1], mdy[2]); -#endif - exec sql rollback; + + ts1 = PGTYPEStimestamp_atot("2003-12-04 17:34:29", NULL); + text = PGTYPEStimestamp_ttoa(ts1); + + printf("date_day of %s is %d\n", text, PGTYPESdate_dayofweek(ts1)); + + PGTYPESdate_today(&date1); + text = PGTYPESdate_dtoa(date1); + printf("today is %s\n", text); + + fmt = "(ddd), mmm. dd, yyyy, repeat: (ddd), mmm. dd, yyyy. end"; + out = (char*) malloc(strlen(fmt) + 1); + + PGTYPESdate_fmtdate(date1, fmt, out); + printf("Today in format \"%s\" is \"%s\"\n", fmt, out); + free(out); + + /* rdefmtdate() */ + + date1 = 0; text = ""; + fmt = "yy/mm/dd"; + in = "In the year 1995, the month of December, it is the 25th day"; + /* 0123456789012345678901234567890123456789012345678901234567890 + * 0 1 2 3 4 5 6 + */ + PGTYPESdate_defmtdate(&date1, fmt, in); + text = PGTYPESdate_dtoa(date1); + printf("defmtdate1: %s\n", text); + + date1 = 0; text = ""; + fmt = "mmmm. dd. yyyy"; + in = "12/25/95"; + PGTYPESdate_defmtdate(&date1, fmt, in); + text = PGTYPESdate_dtoa(date1); + printf("defmtdate2: %s\n", text); + + date1 = 0; text = ""; + fmt = "yy/mm/dd"; + in = "95/12/25"; + PGTYPESdate_defmtdate(&date1, fmt, in); + text = PGTYPESdate_dtoa(date1); + printf("defmtdate3: %s\n", text); + + date1 = 0; text = ""; + fmt = "yy/mm/dd"; + in = "1995, December 25th"; + PGTYPESdate_defmtdate(&date1, fmt, in); + text = PGTYPESdate_dtoa(date1); + printf("defmtdate4: %s\n", text); + + date1 = 0; text = ""; + fmt = "dd-mm-yy"; + in = "This is 25th day of December, 1995"; + PGTYPESdate_defmtdate(&date1, fmt, in); + text = PGTYPESdate_dtoa(date1); + printf("defmtdate5: %s\n", text); + + date1 = 0; text = ""; + fmt = "mmddyy"; + in = "Dec. 25th, 1995"; + PGTYPESdate_defmtdate(&date1, fmt, in); + text = PGTYPESdate_dtoa(date1); + printf("defmtdate6: %s\n", text); + + date1 = 0; text = ""; + fmt = "mmm. dd. yyyy"; + in = "dec 25th 1995"; + PGTYPESdate_defmtdate(&date1, fmt, in); + text = PGTYPESdate_dtoa(date1); + printf("defmtdate7: %s\n", text); + + date1 = 0; text = ""; + fmt = "mmm. dd. yyyy"; + in = "DEC-25-1995"; + PGTYPESdate_defmtdate(&date1, fmt, in); + text = PGTYPESdate_dtoa(date1); + printf("defmtdate8: %s\n", text); + + date1 = 0; text = ""; + fmt = "mm yy dd."; + in = "12199525"; + PGTYPESdate_defmtdate(&date1, fmt, in); + text = PGTYPESdate_dtoa(date1); + printf("defmtdate9: %s\n", text); + + date1 = 0; text = ""; + fmt = "yyyy fierj mm dd."; + in = "19951225"; + PGTYPESdate_defmtdate(&date1, fmt, in); + text = PGTYPESdate_dtoa(date1); + printf("defmtdate10: %s\n", text); + + date1 = 0; text = ""; + fmt = "mm/dd/yy"; + in = "122595"; + PGTYPESdate_defmtdate(&date1, fmt, in); + text = PGTYPESdate_dtoa(date1); + printf("defmtdate12: %s\n", text); + + exec sql rollback; exec sql disconnect; if (dbgs != NULL)