OSDN Git Service

1) Fix a few bugs about SQLGetData()
authorHiroshi Inoue <inoue@tpf.co.jp>
Mon, 5 Nov 2001 09:46:17 +0000 (09:46 +0000)
committerHiroshi Inoue <inoue@tpf.co.jp>
Mon, 5 Nov 2001 09:46:17 +0000 (09:46 +0000)
   reported by Mika Mantyla.
2) Timestamp precision.
3) Separate ODBC3.0 files.

13 files changed:
src/interfaces/odbc/bind.c
src/interfaces/odbc/bind.h
src/interfaces/odbc/columninfo.c
src/interfaces/odbc/convert.c
src/interfaces/odbc/convert.h
src/interfaces/odbc/info.c
src/interfaces/odbc/odbcapi30.c
src/interfaces/odbc/pgtypes.c
src/interfaces/odbc/pgtypes.h
src/interfaces/odbc/psqlodbc.h
src/interfaces/odbc/psqlodbc.rc
src/interfaces/odbc/statement.c
src/interfaces/odbc/win32.mak

index d176ace..e9f5cc3 100644 (file)
@@ -424,6 +424,8 @@ create_empty_bindings(int num_columns)
                new_bindings[i].buffer = NULL;
                new_bindings[i].used = NULL;
                new_bindings[i].data_left = -1;
+               new_bindings[i].ttlbuf = NULL;
+               new_bindings[i].ttlbuflen = 0;
        }
 
        return new_bindings;
index 444d30f..363abb0 100644 (file)
@@ -22,6 +22,8 @@ struct BindInfoClass_
        char       *buffer;                     /* pointer to the buffer */
        Int4       *used;                       /* used space in the buffer (for strings
                                                                 * not counting the '\0') */
+       char            *ttlbuf;                /* to save the large result */
+       Int4            ttlbuflen;              /* the buffer length */
        Int2            returntype;             /* kind of conversion to be applied when
                                                                 * returning (SQL_C_DEFAULT,
                                                                 * SQL_C_CHAR...) */
index d9a22a1..7fe72d3 100644 (file)
@@ -12,6 +12,7 @@
  *-------
  */
 
+#include "pgtypes.h"
 #include "columninfo.h"
 
 #include "connection.h"
@@ -95,7 +96,16 @@ CI_read_fields(ColumnInfoClass *self, ConnectionClass *conn)
                        new_atttypmod = (Int4) SOCK_get_int(sock, 4);
 
                        /* Subtract the header length */
-                       new_atttypmod -= 4;
+                       switch (new_adtid)
+                       {
+                               case PG_TYPE_DATETIME:
+                               case PG_TYPE_TIMESTAMP_NO_TMZONE:
+                               case PG_TYPE_TIME:
+                               case PG_TYPE_TIME_WITH_TMZONE:
+                                       break;
+                               default:
+                                       new_atttypmod -= 4;
+                       }
                        if (new_atttypmod < 0)
                                new_atttypmod = -1;
 
index 871a9c3..f284b16 100644 (file)
 #include "connection.h"
 #include "pgapifunc.h"
 
+#ifdef __CYGWIN__
+#define TIMEZONE_GLOBAL        _timezone
+#elif  defined(WIN32) || defined(HAVE_INT_TIMEZONE)
+#define        TIMEZONE_GLOBAL timezone
+#endif
 
 /*
  *     How to map ODBC scalar functions {fn func(args)} to Postgres.
@@ -136,6 +141,156 @@ static char *conv_to_octal(unsigned char val);
 
 
 
+/*     
+ *     TIMESTAMP <-----> SIMPLE_TIME
+ *             precision support since 7.2.
+ *             time zone support is unavailable(the stuff is unreliable)
+ */
+static BOOL timestamp2stime(const char * str, SIMPLE_TIME *st, BOOL *bZone, int *zone)
+{
+       char    rest[64], *ptr;
+       int     scnt, i;
+       long            timediff;
+       BOOL    withZone = *bZone;
+
+       *bZone = FALSE;
+       *zone = 0;
+       st->fr = 0;
+       if ((scnt = sscanf(str, "%4d-%2d-%2d %2d:%2d:%2d%s", &st->y, &st->m, &st->d, &st->hh, &st->mm, &st->ss, rest)) < 6)
+               return FALSE;
+       else if (scnt == 6)
+               return TRUE;
+       switch (rest[0])
+       {
+               case '+':
+                       *bZone = TRUE;
+                       *zone = atoi(&rest[1]);
+                       break;
+               case '-':
+                       *bZone = TRUE;
+                       *zone = -atoi(&rest[1]);
+                       break;
+               case '.':
+                       if ((ptr = strchr(rest, '+')) != NULL)
+                       {
+                               *bZone = TRUE;
+                               *zone = atoi(&ptr[1]);
+                               *ptr = '\0';
+                       }
+                       else if ((ptr = strchr(rest, '-')) != NULL)
+                       {
+                               *bZone = TRUE;
+                               *zone = -atoi(&ptr[1]);
+                               *ptr = '\0';
+                       }
+                       for (i = 1; i < 10; i++)
+                       {
+                               if (!isdigit(rest[i]))
+                                       break;
+                       }
+                       for (; i < 10; i++)
+                               rest[i] = '0';
+                       rest[i] = '\0';
+                       st->fr = atoi(&rest[1]);
+                       break;
+               default:
+                       return  TRUE;
+       }
+       if (!withZone || !*bZone || st->y < 1970)
+               return TRUE;
+#if defined(WIN32) || defined(HAVE_INT_TIMEZONE)
+       if (!tzname[0] || !tzname[0][0])
+       {
+               *bZone = FALSE;
+               return TRUE;
+       }
+       timediff = TIMEZONE_GLOBAL + (*zone) * 3600;
+       if (!daylight && timediff == 0) /* the same timezone */
+               return TRUE;
+       else
+       {
+               struct tm       tm, *tm2;
+               time_t          time0;
+
+               *bZone = FALSE;
+               tm.tm_year = st->y - 1900;
+               tm.tm_mon = st->m - 1;
+               tm.tm_mday = st->d;
+               tm.tm_hour = st->hh;
+               tm.tm_min = st->mm;
+               tm.tm_sec = st->ss;
+               tm.tm_isdst = -1;
+               time0 = mktime(&tm);
+               if (time0 < 0)
+                       return TRUE;
+               if (tm.tm_isdst > 0)
+                       timediff -= 3600;
+               if (timediff == 0) /* the same time zone */
+                       return TRUE;
+               time0 -= timediff;
+               if (time0 >= 0 && (tm2 = localtime(&time0)) != NULL)
+               {
+                       st->y = tm2->tm_year + 1900;
+                       st->m = tm2->tm_mon + 1;
+                       st->d = tm2->tm_mday;
+                       st->hh= tm2->tm_hour;
+                       st->mm= tm2->tm_min;
+                       st->ss= tm2->tm_sec;
+                       *bZone = TRUE;
+               }
+       }
+#endif /* WIN32 */
+       return  TRUE;
+}
+
+static BOOL stime2timestamp(const SIMPLE_TIME *st, char * str, BOOL bZone, BOOL precision)
+{
+       char    precstr[16], zonestr[16];
+       int     i;
+
+       precstr[0] = '\0';
+       if (precision && st->fr)
+       {
+               sprintf(precstr, ".%09d", st->fr);
+               for (i = 9; i > 0; i--)
+               {
+                       if (precstr[i] != '0')
+                               break;
+                       precstr[i] = '\0';
+               }
+       }
+       zonestr[0] = '\0';
+#if defined(WIN32) || defined(HAVE_INT_TIMEZONE)
+       if (bZone && tzname[0] && tzname[0][0] && st->y >= 1970)
+       {
+               long    zoneint;
+               struct tm       tm;
+               time_t          time0;
+
+               zoneint = TIMEZONE_GLOBAL;
+               if (daylight && st->y >=1900)
+               { 
+                       tm.tm_year = st->y - 1900;
+                       tm.tm_mon = st->m - 1;
+                       tm.tm_mday = st->d;
+                       tm.tm_hour = st->hh;
+                       tm.tm_min = st->mm;
+                       tm.tm_sec = st->ss;
+                       tm.tm_isdst = -1;
+                       time0 = mktime(&tm);
+                       if (time0 >= 0 && tm.tm_isdst > 0)
+                               zoneint -= 3600;
+               }
+               if (zoneint > 0)
+                       sprintf(zonestr, "-%02d", (int)zoneint / 3600);
+               else
+                       sprintf(zonestr, "+%02d", -(int)zoneint / 3600);
+       }
+#endif /* WIN32 */
+       sprintf(str, "%.4d-%.2d-%.2d %.2d:%.2d:%.2d%s%s", st->y, st->m, st->d, st->hh, st->mm, st->ss, precstr, zonestr);
+       return  TRUE;
+}
+
 /*     This is called by SQLFetch() */
 int
 copy_and_convert_field_bindinfo(StatementClass *stmt, Int4 field_type, void *value, int col)
@@ -165,14 +320,29 @@ copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, Int2
        int                     bind_size = stmt->options.bind_size;
        int                     result = COPY_OK;
        BOOL            changed;
-       static char *tempBuf = NULL;
-       static unsigned int tempBuflen = 0;
        const char *neut_str = value;
        char            midtemp[2][32];
        int                     mtemp_cnt = 0;
+       static  BindInfoClass   sbic;
+       BindInfoClass           *pbic;
 
-       if (!tempBuf)
-               tempBuflen = 0;
+       if (stmt->current_col >= 0)
+       {
+               pbic = &stmt->bindings[stmt->current_col];
+               if (pbic->data_left == -2)
+                       pbic->data_left = (cbValueMax > 0) ? 0 : -1;    /* This seems to be * needed for ADO ? */
+               if (pbic->data_left == 0)
+               {
+                       if (pbic->ttlbuf != NULL)
+                       {
+                               free(pbic->ttlbuf);
+                               pbic->ttlbuf = NULL;
+                               pbic->ttlbuflen = 0;
+                       }
+                       pbic->data_left = -2; /* needed by ADO ? */
+                       return  COPY_NO_DATA_FOUND;
+               }
+       }
        /*---------
         *      rgbValueOffset is *ONLY* for character and binary data.
         *      pcbValueOffset is for computing any pcbValue location
@@ -243,8 +413,15 @@ copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, Int2
                case PG_TYPE_ABSTIME:
                case PG_TYPE_DATETIME:
                case PG_TYPE_TIMESTAMP:
+                       st.fr = 0;
                        if (strnicmp(value, "invalid", 7) != 0)
-                               sscanf(value, "%4d-%2d-%2d %2d:%2d:%2d", &st.y, &st.m, &st.d, &st.hh, &st.mm, &st.ss);
+                       {
+                               BOOL    bZone = (field_type != PG_TYPE_TIMESTAMP_NO_TMZONE && PG_VERSION_GE(SC_get_conn(stmt), 7.2));
+                               int     zone;
+                               /*sscanf(value, "%4d-%2d-%2d %2d:%2d:%2d", &st.y, &st.m, &st.d, &st.hh, &st.mm, &st.ss);*/
+                               bZone = FALSE; /* time zone stuff is unreliable */
+                               timestamp2stime(value, &st, &bZone, &zone);
+                       }
                        else
                        {
                                /*
@@ -421,10 +598,14 @@ copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, Int2
                                break;
 
                        default:
-                               if (stmt->current_col >= 0 && stmt->bindings[stmt->current_col].data_left == -2)
-                                       stmt->bindings[stmt->current_col].data_left = (cbValueMax > 0) ? 0 : -1;        /* This seems to be
-                                                                                                                                                                                                * needed for ADO ? */
-                               if (stmt->current_col < 0 || stmt->bindings[stmt->current_col].data_left < 0)
+                               if (stmt->current_col < 0)
+                               {
+                                       pbic = &sbic;
+                                       pbic->data_left = -1;
+                               }
+                               else
+                                       pbic = &stmt->bindings[stmt->current_col];
+                               if (pbic->data_left < 0)
                                {
                                        /* convert linefeeds to carriage-return/linefeed */
                                        len = convert_linefeeds(neut_str, NULL, 0, &changed);
@@ -434,51 +615,42 @@ copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, Int2
                                                result = COPY_RESULT_TRUNCATED;
                                                break;
                                        }
+                                       if (!pbic->ttlbuf)
+                                               pbic->ttlbuflen = 0;
                                        if (changed || len >= cbValueMax)
                                        {
-                                               if (len >= (int) tempBuflen)
+                                               if (len >= (int) pbic->ttlbuflen)
                                                {
-                                                       tempBuf = realloc(tempBuf, len + 1);
-                                                       tempBuflen = len + 1;
+                                                       pbic->ttlbuf = realloc(pbic->ttlbuf, len + 1);
+                                                       pbic->ttlbuflen = len + 1;
                                                }
-                                               convert_linefeeds(neut_str, tempBuf, tempBuflen, &changed);
-                                               ptr = tempBuf;
+                                               convert_linefeeds(neut_str, pbic->ttlbuf, pbic->ttlbuflen, &changed);
+                                               ptr = pbic->ttlbuf;
                                        }
                                        else
                                        {
-                                               if (tempBuf)
+                                               if (pbic->ttlbuf)
                                                {
-                                                       free(tempBuf);
-                                                       tempBuf = NULL;
+                                                       free(pbic->ttlbuf);
+                                                       pbic->ttlbuf = NULL;
                                                }
                                                ptr = neut_str;
                                        }
                                }
                                else
-                                       ptr = tempBuf;
+                                       ptr = pbic->ttlbuf;
 
                                mylog("DEFAULT: len = %d, ptr = '%s'\n", len, ptr);
 
                                if (stmt->current_col >= 0)
                                {
-                                       if (stmt->bindings[stmt->current_col].data_left == 0)
-                                       {
-                                               if (tempBuf)
-                                               {
-                                                       free(tempBuf);
-                                                       tempBuf = NULL;
-                                               }
-                                               /* The following seems to be needed for ADO ? */
-                                               stmt->bindings[stmt->current_col].data_left = -2;
-                                               return COPY_NO_DATA_FOUND;
-                                       }
-                                       else if (stmt->bindings[stmt->current_col].data_left > 0)
+                                       if (pbic->data_left > 0)
                                        {
-                                               ptr += strlen(ptr) - stmt->bindings[stmt->current_col].data_left;
-                                               len = stmt->bindings[stmt->current_col].data_left;
+                                               ptr += strlen(ptr) - pbic->data_left;
+                                               len = pbic->data_left;
                                        }
                                        else
-                                               stmt->bindings[stmt->current_col].data_left = len;
+                                               pbic->data_left = len;
                                }
 
                                if (cbValueMax > 0)
@@ -491,7 +663,7 @@ copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, Int2
 
                                        /* Adjust data_left for next time */
                                        if (stmt->current_col >= 0)
-                                               stmt->bindings[stmt->current_col].data_left -= copy_len;
+                                               pbic->data_left -= copy_len;
                                }
 
                                /*
@@ -502,10 +674,10 @@ copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, Int2
                                        result = COPY_RESULT_TRUNCATED;
                                else
                                {
-                                       if (tempBuf)
+                                       if (pbic->ttlbuf != NULL)
                                        {
-                                               free(tempBuf);
-                                               tempBuf = NULL;
+                                               free(pbic->ttlbuf);
+                                               pbic->ttlbuf = NULL;
                                        }
                                }
 
@@ -537,6 +709,9 @@ copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, Int2
                switch (fCType)
                {
                        case SQL_C_DATE:
+#if (ODBCVER >= 0x0300)
+                       case SQL_C_TYPE_DATE: /* 91 */
+#endif
                                len = 6;
                                {
                                        DATE_STRUCT *ds;
@@ -552,6 +727,9 @@ copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, Int2
                                break;
 
                        case SQL_C_TIME:
+#if (ODBCVER >= 0x0300)
+                       case SQL_C_TYPE_TIME: /* 92 */
+#endif
                                len = 6;
                                {
                                        TIME_STRUCT *ts;
@@ -567,6 +745,9 @@ copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, Int2
                                break;
 
                        case SQL_C_TIMESTAMP:
+#if (ODBCVER >= 0x0300)
+                       case SQL_C_TYPE_TIMESTAMP: /* 93 */
+#endif
                                len = 16;
                                {
                                        TIMESTAMP_STRUCT *ts;
@@ -581,7 +762,7 @@ copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, Int2
                                        ts->hour = st.hh;
                                        ts->minute = st.mm;
                                        ts->second = st.ss;
-                                       ts->fraction = 0;
+                                       ts->fraction = st.fr;
                                }
                                break;
 
@@ -671,37 +852,38 @@ copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, Int2
                                /* truncate if necessary */
                                /* convert octal escapes to bytes */
 
-                               if (len = strlen(neut_str), len >= (int) tempBuflen)
+                               if (stmt->current_col < 0)
                                {
-                                       tempBuf = realloc(tempBuf, len + 1);
-                                       tempBuflen = len + 1;
+                                       pbic = &sbic;
+                                       pbic->data_left = -1;
                                }
-                               len = convert_from_pgbinary(neut_str, tempBuf, tempBuflen);
-                               ptr = tempBuf;
+                               else
+                                       pbic = &stmt->bindings[stmt->current_col];
+                               if (!pbic->ttlbuf)
+                                       pbic->ttlbuflen = 0;
+                               if (len = strlen(neut_str), len >= (int) pbic->ttlbuflen)
+                               {
+                                       pbic->ttlbuf = realloc(pbic->ttlbuf, len + 1);
+                                       pbic->ttlbuflen = len + 1;
+                               }
+                               len = convert_from_pgbinary(neut_str, pbic->ttlbuf, pbic->ttlbuflen);
+                               ptr = pbic->ttlbuf;
 
                                if (stmt->current_col >= 0)
                                {
-                                       /* No more data left for this column */
-                                       if (stmt->bindings[stmt->current_col].data_left == 0)
-                                       {
-                                               free(tempBuf);
-                                               tempBuf = NULL;
-                                               return COPY_NO_DATA_FOUND;
-                                       }
-
                                        /*
                                         * Second (or more) call to SQLGetData so move the
                                         * pointer
                                         */
-                                       else if (stmt->bindings[stmt->current_col].data_left > 0)
+                                       if (pbic->data_left > 0)
                                        {
-                                               ptr += len - stmt->bindings[stmt->current_col].data_left;
-                                               len = stmt->bindings[stmt->current_col].data_left;
+                                               ptr += len - pbic->data_left;
+                                               len = pbic->data_left;
                                        }
 
                                        /* First call to SQLGetData so initialize data_left */
                                        else
-                                               stmt->bindings[stmt->current_col].data_left = len;
+                                               pbic->data_left = len;
 
                                }
 
@@ -714,7 +896,7 @@ copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, Int2
 
                                        /* Adjust data_left for next time */
                                        if (stmt->current_col >= 0)
-                                               stmt->bindings[stmt->current_col].data_left -= copy_len;
+                                               pbic->data_left -= copy_len;
                                }
 
                                /*
@@ -724,10 +906,10 @@ copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, Int2
                                if (len > cbValueMax)
                                        result = COPY_RESULT_TRUNCATED;
 
-                               if (tempBuf)
+                               if (pbic->ttlbuf)
                                {
-                                       free(tempBuf);
-                                       tempBuf = NULL;
+                                       free(pbic->ttlbuf);
+                                       pbic->ttlbuf = NULL;
                                }
                                mylog("SQL_C_BINARY: len = %d, copy_len = %d\n", len, copy_len);
                                break;
@@ -741,6 +923,8 @@ copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, Int2
        if (pcbValue)
                *(SDWORD *) ((char *) pcbValue + pcbValueOffset) = len;
 
+       if (result == COPY_OK && stmt->current_col >=0)
+               stmt->bindings[stmt->current_col].data_left = 0;
        return result;
 
 }
@@ -1406,6 +1590,9 @@ copy_statement_with_parameters(StatementClass *stmt)
                                }
 
                        case SQL_C_DATE:
+#if (ODBCVER >= 0x0300)
+                       case SQL_C_TYPE_DATE: /* 91 */
+#endif
                                {
                                        DATE_STRUCT *ds = (DATE_STRUCT *) buffer;
 
@@ -1417,6 +1604,9 @@ copy_statement_with_parameters(StatementClass *stmt)
                                }
 
                        case SQL_C_TIME:
+#if (ODBCVER >= 0x0300)
+                       case SQL_C_TYPE_TIME: /* 92 */
+#endif
                                {
                                        TIME_STRUCT *ts = (TIME_STRUCT *) buffer;
 
@@ -1428,6 +1618,9 @@ copy_statement_with_parameters(StatementClass *stmt)
                                }
 
                        case SQL_C_TIMESTAMP:
+#if (ODBCVER >= 0x0300)
+                       case SQL_C_TYPE_TIMESTAMP: /* 93 */
+#endif
                                {
                                        TIMESTAMP_STRUCT *tss = (TIMESTAMP_STRUCT *) buffer;
 
@@ -1437,6 +1630,7 @@ copy_statement_with_parameters(StatementClass *stmt)
                                        st.hh = tss->hour;
                                        st.mm = tss->minute;
                                        st.ss = tss->second;
+                                       st.fr = tss->fraction;
 
                                        mylog("m=%d,d=%d,y=%d,hh=%d,mm=%d,ss=%d\n", st.m, st.d, st.y, st.hh, st.mm, st.ss);
 
@@ -1487,6 +1681,9 @@ copy_statement_with_parameters(StatementClass *stmt)
                                break;
 
                        case SQL_DATE:
+#if (ODBCVER >= 0x0300)
+                       case SQL_TYPE_DATE: /* 91 */
+#endif
                                if (buf)
                                {                               /* copy char data to time */
                                        my_strcpy(cbuf, sizeof(cbuf), buf, used);
@@ -1499,6 +1696,9 @@ copy_statement_with_parameters(StatementClass *stmt)
                                break;
 
                        case SQL_TIME:
+#if (ODBCVER >= 0x0300)
+                       case SQL_TYPE_TIME: /* 92 */
+#endif
                                if (buf)
                                {                               /* copy char data to time */
                                        my_strcpy(cbuf, sizeof(cbuf), buf, used);
@@ -1511,6 +1711,9 @@ copy_statement_with_parameters(StatementClass *stmt)
                                break;
 
                        case SQL_TIMESTAMP:
+#if (ODBCVER >= 0x0300)
+                       case SQL_TYPE_TIMESTAMP: /* 93 */
+#endif
 
                                if (buf)
                                {
@@ -1518,8 +1721,12 @@ copy_statement_with_parameters(StatementClass *stmt)
                                        parse_datetime(cbuf, &st);
                                }
 
-                               sprintf(tmp, "'%.4d-%.2d-%.2d %.2d:%.2d:%.2d'",
-                                               st.y, st.m, st.d, st.hh, st.mm, st.ss);
+                               /* sprintf(tmp, "'%.4d-%.2d-%.2d %.2d:%.2d:%.2d'",
+                                               st.y, st.m, st.d, st.hh, st.mm, st.ss);*/
+                               tmp[0] = '\'';
+                               /* Time zone stuff is unreliable */
+                               stime2timestamp(&st, tmp + 1, FALSE, PG_VERSION_GE(conn, 7.2));
+                               strcat(tmp, "'");
 
                                CVT_APPEND_STR(tmp);
 
@@ -2203,7 +2410,43 @@ decode(const char *in, char *out)
        out[o++] = '\0';
 }
 
-
+static const char *hextbl = "0123456789ABCDEF";
+static int
+pg_bin2hex(UCHAR *src, UCHAR *dst, int length)
+{
+       UCHAR   chr, *src_wk, *dst_wk;
+       BOOL    backwards;
+       int     i;
+       
+       backwards = FALSE;
+       if (dst < src)
+       {
+               if (dst + length > src + 1)
+                       return -1;
+       }
+       else if (dst < src + length)
+               backwards = TRUE;
+       if (backwards)
+       {
+               for (i = 0, src_wk = src + length - 1, dst_wk = dst + 2 * length - 1; i < length; i++, src_wk--)
+               {
+                       chr = *src_wk;
+                       *dst_wk-- = hextbl[chr % 16];
+                       *dst_wk-- = hextbl[chr >> 4];
+               }
+       }
+       else
+       {
+               for (i = 0, src_wk = src, dst_wk = dst; i < length; i++, src_wk++)
+               {
+                       chr = *src_wk;
+                       *dst_wk++ = hextbl[chr >> 4];
+                       *dst_wk++ = hextbl[chr % 16];
+               }
+       }
+       dst[2 * length] = '\0';
+       return length;
+}
 /*-------
  *     1. get oid (from 'value')
  *     2. open the large object
@@ -2231,6 +2474,7 @@ convert_lo(StatementClass *stmt, const void *value, Int2 fCType, PTR rgbValue,
        BindInfoClass *bindInfo = NULL;
        ConnectionClass *conn = SC_get_conn(stmt);
        ConnInfo   *ci = &(conn->connInfo);
+       int     factor = (fCType == SQL_C_CHAR ? 2 : 1);
 
        /* If using SQLGetData, then current_col will be set */
        if (stmt->current_col >= 0)
@@ -2304,7 +2548,7 @@ convert_lo(StatementClass *stmt, const void *value, Int2 fCType, PTR rgbValue,
                return COPY_GENERAL_ERROR;
        }
 
-       retval = lo_read(conn, stmt->lobj_fd, (char *) rgbValue, cbValueMax);
+       retval = lo_read(conn, stmt->lobj_fd, (char *) rgbValue, factor > 1 ? (cbValueMax - 1) / factor : cbValueMax);
        if (retval < 0)
        {
                lo_close(conn, stmt->lobj_fd);
@@ -2341,13 +2585,15 @@ convert_lo(StatementClass *stmt, const void *value, Int2 fCType, PTR rgbValue,
                return COPY_GENERAL_ERROR;
        }
 
+       if (factor > 1)
+               pg_bin2hex((char *) rgbValue, (char *) rgbValue, retval);
        if (retval < left)
                result = COPY_RESULT_TRUNCATED;
        else
                result = COPY_OK;
 
        if (pcbValue)
-               *pcbValue = left < 0 ? SQL_NO_TOTAL : left;
+               *pcbValue = left < 0 ? SQL_NO_TOTAL : left * factor;
 
        if (bindInfo && bindInfo->data_left > 0)
                bindInfo->data_left -= retval;
index dfbd32c..2257fb2 100644 (file)
@@ -27,7 +27,8 @@ typedef struct
        int                     hh;
        int                     mm;
        int                     ss;
-} SIMPLE_TIME;
+       int                     fr;
+}                      SIMPLE_TIME;
 
 int                    copy_and_convert_field_bindinfo(StatementClass *stmt, Int4 field_type, void *value, int col);
 int copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, Int2 fCType,
index 09439b2..23291b5 100644 (file)
@@ -216,32 +216,6 @@ PGAPI_GetInfo(
 
                case SQL_DRIVER_ODBC_VER:
                        p = DRIVER_ODBC_VER;
-#ifdef DRIVER_CURSOR_IMPLEMENT
-                       {
-                               static char dver[32];
-
-                               SQLGetPrivateProfileString(DBMS_NAME,
-                               "DriverODBCVer", "", dver, sizeof(dver), "odbcinst.ini");
-                               if (dver[0])
-                               {
-                                       int                     major,
-                                                               minor;
-
-                                       mylog("REGISTRY_ODBC_VER = %s\n", dver)
-                                               ;
-                                       if (sscanf(dver, "%x.%x", &major, &minor) >= 2)
-                                       {
-                                               Int2            drv_ver = (major << 8) + minor;
-
-                                               if (drv_ver > ODBCVER)
-                                               {
-                                                       conn->driver_version = drv_ver;
-                                                       p = dver;
-                                               }
-                                       }
-                               }
-                       }
-#endif  /* DRIVER_CURSOR_IMPLEMENT */
                        break;
 
                case SQL_DRIVER_VER:    /* ODBC 1.0 */
@@ -842,6 +816,7 @@ PGAPI_GetFunctions(
 
        if (fFunction == SQL_API_ALL_FUNCTIONS)
        {
+#if (ODBCVER < 0x0300)
                if (ci->drivers.lie)
                {
                        int                     i;
@@ -856,6 +831,7 @@ PGAPI_GetFunctions(
                                pfExists[i] = TRUE;
                }
                else
+#endif
                {
                        memset(pfExists, 0, sizeof(UWORD) * 100);
 
@@ -2685,7 +2661,7 @@ PGAPI_PrimaryKeys(
 /*
  *     Multibyte support stuff for SQLForeignKeys().
  *     There may be much more effective way in the
- *     future version. The way is very forcive currently.
+ *     future version. The way is very forcible currently.
  */
 static BOOL
 isMultibyte(const unsigned char *str)
index 5a63748..9de10a9 100644 (file)
@@ -18,8 +18,8 @@
  *-------
  */
 
-#ifndef ODBCVER_REP
-#define ODBCVER_REP 0x0300
+#ifndef ODBCVER
+#define ODBCVER 0x0300
 #endif
 #include "psqlodbc.h"
 #include <stdio.h>
@@ -344,7 +344,7 @@ SQLGetStmtAttr(HSTMT StatementHandle,
                        len = 4;
                        break;
                case SQL_ATTR_AUTO_IPD: /* 10001 */
-               case SQL_ATTR_ROW_BIND_TYPE:    /* == SQL_BIND_TYPE */
+               /* case SQL_ATTR_ROW_BIND_TYPE: ** == SQL_BIND_TYPE(ODBC2.0) */
                case SQL_ATTR_PARAMSET_SIZE:    /* 22 */
                case SQL_ATTR_PARAM_STATUS_PTR: /* 20 */
                case SQL_ATTR_PARAMS_PROCESSED_PTR:             /* 21 */
@@ -484,7 +484,7 @@ SQLSetStmtAttr(HSTMT StatementHandle,
                case SQL_ATTR_APP_ROW_DESC:             /* 10010 */
                case SQL_ATTR_APP_PARAM_DESC:   /* 10011 */
                case SQL_ATTR_AUTO_IPD: /* 10001 */
-                       /* case SQL_ATTR_ROW_BIND_TYPE: */      /* == SQL_BIND_TYPE */
+               /* case SQL_ATTR_ROW_BIND_TYPE: ** == SQL_BIND_TYPE(ODBC2.0) */
                case SQL_ATTR_IMP_ROW_DESC:             /* 10012 */
                case SQL_ATTR_IMP_PARAM_DESC:   /* 10013 */
                case SQL_ATTR_METADATA_ID:              /* 10014 */
index 1f177a1..0a7bd35 100644 (file)
@@ -536,6 +536,67 @@ getCharPrecision(StatementClass *stmt, Int4 type, int col, int handle_unknown_si
                return p;
 }
 
+static Int2
+getTimestampScale(StatementClass *stmt, Int4 type, int col)
+{
+       ConnectionClass *conn = SC_get_conn (stmt);
+       Int4            atttypmod;
+       QResultClass *result;
+       ColumnInfoClass *flds;
+
+       mylog("getTimestampScale: type=%d, col=%d\n", type, col);
+
+       if (col < 0)
+               return 0;
+       if (PG_VERSION_LT(conn, 7.2))
+               return 0;
+
+       result = SC_get_Result(stmt);
+
+       /*
+        * Manual Result Sets -- use assigned column width (i.e., from
+        * set_tuplefield_string)
+        */
+       atttypmod = 0;
+       if (stmt->manual_result)
+       {
+               flds = result->fields;
+               if (flds)
+                       atttypmod = flds->atttypmod[col];
+mylog("atttypmod1=%d\n", atttypmod);
+       }
+       else 
+               atttypmod = QR_get_atttypmod(result, col);
+mylog("atttypmod2=%d\n", atttypmod);
+       return (atttypmod > -1 ? atttypmod : 0);
+}
+
+
+static Int4
+getTimestampPrecision(StatementClass *stmt, Int4 type, int col)
+{
+       Int4    fixed, scale;
+
+       mylog("getTimestampPrecision: type=%d, col=%d\n", type, col);
+
+       switch (type)
+       {
+               case PG_TYPE_TIME:
+                       fixed = 8;
+                       break;
+               case PG_TYPE_TIME_WITH_TMZONE:
+                       fixed = 11;
+                       break;
+               case PG_TYPE_TIMESTAMP_NO_TMZONE:
+                       fixed = 19;
+                       break;
+               default:
+                       fixed = 22;
+                       break;
+       }
+       scale = getTimestampScale(stmt, type, col);     
+       return (scale > 0) ? fixed + 1 + scale : fixed; 
+}
 
 /*
  *     For PG_TYPE_VARCHAR, PG_TYPE_BPCHAR, PG_TYPE_NUMERIC, SQLColumns will
@@ -591,7 +652,8 @@ pgtype_precision(StatementClass *stmt, Int4 type, int col, int handle_unknown_si
                case PG_TYPE_TIMESTAMP:
                        return 22;
                case PG_TYPE_DATETIME:
-                       return 22;
+                       /* return 22; */
+                       return getTimestampPrecision(stmt, type, col);
 
                case PG_TYPE_BOOL:
                        return 1;
@@ -728,7 +790,8 @@ pgtype_scale(StatementClass *stmt, Int4 type, int col)
                case PG_TYPE_TIMESTAMP:
                        return 0;
                case PG_TYPE_DATETIME:
-                       return 0;
+                       /* return 0; */
+                       return getTimestampScale(stmt, type, col);
 
                case PG_TYPE_NUMERIC:
                        return getNumericScale(stmt, type, col);
index 7bd33cf..0e6a1cc 100644 (file)
 #define PG_TYPE_VARCHAR                        1043
 #define PG_TYPE_DATE                   1082
 #define PG_TYPE_TIME                   1083
+#define PG_TYPE_TIMESTAMP_NO_TMZONE    1114    /* since 7.2 */
 #define PG_TYPE_DATETIME               1184
-#define PG_TYPE_TIMESTAMP              1296
+#define PG_TYPE_TIME_WITH_TMZONE       1266    /* since 7.1 */
+#define PG_TYPE_TIMESTAMP              1296    /* deprecated since 7.0 */
 #define PG_TYPE_NUMERIC                        1700
 
 /* extern Int4 pgtypes_defined[]; */
index 540e295..62e6b9b 100644 (file)
@@ -5,7 +5,7 @@
  *
  * Comments:           See "notice.txt" for copyright and license information.
  *
- * $Id: psqlodbc.h,v 1.53 2001/10/28 06:26:14 momjian Exp $
+ * $Id: psqlodbc.h,v 1.54 2001/11/05 09:46:17 inoue Exp $
  *
  */
 
@@ -21,9 +21,7 @@
 #include <stdio.h>                             /* for FILE* pointers: see GLOBAL_VALUES */
 
 /* Must come before sql.h */
-#ifdef ODBCVER_REP
-#define ODBCVER                                                ODBCVER_REP
-#else
+#ifndef        ODBCVER
 #define ODBCVER                                                0x0250
 #endif  /* ODBCVER_REP */
 
@@ -77,18 +75,27 @@ typedef UInt4 Oid;
 #endif
 
 /* Driver stuff */
-#define DRIVER_ODBC_VER                                "02.50"
 
 #define DRIVERNAME                                     "PostgreSQL ODBC"
+#if (ODBCVER >= 0x0300)
+#define DRIVER_ODBC_VER                                "03.00"
+#define DBMS_NAME                                      "PostgreSQL30"
+#else
+#define DRIVER_ODBC_VER                                "02.50"
 #define DBMS_NAME                                      "PostgreSQL"
+#endif /* ODBCVER */
 
-#define POSTGRESDRIVERVERSION          "07.01.0008"
+#define POSTGRESDRIVERVERSION          "07.01.0009"
 
 #ifdef WIN32
+#if (ODBCVER >= 0x0300)
+#define DRIVER_FILE_NAME                       "PSQLODBC30.DLL"
+#else
 #define DRIVER_FILE_NAME                       "PSQLODBC.DLL"
+#endif /* ODBCVER */
 #else
 #define DRIVER_FILE_NAME                       "libpsqlodbc.so"
-#endif
+#endif /* WIN32 */
 
 /* Limits */
 #ifdef WIN32
index a6c9b23..30a7ff7 100644 (file)
@@ -354,8 +354,8 @@ END
 //
 
 VS_VERSION_INFO VERSIONINFO
- FILEVERSION 7,1,0,8
- PRODUCTVERSION 7,1,0,8
+ FILEVERSION 7,1,0,9
+ PRODUCTVERSION 7,1,0,9
  FILEFLAGSMASK 0x3L
 #ifdef _DEBUG
  FILEFLAGS 0x1L
@@ -377,14 +377,14 @@ BEGIN
             VALUE "CompanyName", "Insight Distribution Systems\0"
 #endif
             VALUE "FileDescription", "PostgreSQL Driver\0"
-            VALUE "FileVersion", " 07.01.0008\0"
+            VALUE "FileVersion", " 07.01.0009\0"
             VALUE "InternalName", "psqlodbc\0"
             VALUE "LegalCopyright", "\0"
             VALUE "LegalTrademarks", "ODBC(TM) is a trademark of Microsoft Corporation.  Microsoft® is a registered trademark of Microsoft Corporation. Windows(TM) is a trademark of Microsoft Corporation.\0"
             VALUE "OriginalFilename", "psqlodbc.dll\0"
             VALUE "PrivateBuild", "\0"
             VALUE "ProductName", "Microsoft Open Database Connectivity\0"
-            VALUE "ProductVersion", " 07.01.0008\0"
+            VALUE "ProductVersion", " 07.01.0009\0"
             VALUE "SpecialBuild", "\0"
         END
     END
index b4e33d0..b279850 100644 (file)
@@ -320,7 +320,15 @@ SC_Destructor(StatementClass *self)
         */
        /* about that here. */
        if (self->bindings)
+       {
+               int     lf;
+               for (lf = 0; lf < self->bindings_allocated; lf++)
+               {
+                       if (self->bindings[lf].ttlbuf != NULL)
+                               free(self->bindings[lf].ttlbuf);
+               }
                free(self->bindings);
+       }
 
        /* Free the parsed table information */
        if (self->ti)
index 0158adb..6d83b1c 100644 (file)
@@ -84,7 +84,6 @@ CLEAN :
        -@erase "$(INTDIR)\tuple.obj"
        -@erase "$(INTDIR)\tuplelist.obj"
        -@erase "$(INTDIR)\odbcapi.obj"
-       -@erase "$(INTDIR)\odbcapi30.obj"
        -@erase "$(INTDIR)\vc60.idb"
        -@erase "$(OUTDIR)\psqlodbc.dll"
        -@erase "$(OUTDIR)\psqlodbc.exp"
@@ -169,7 +168,6 @@ LINK32_OBJS= \
        "$(INTDIR)\tuple.obj" \
        "$(INTDIR)\tuplelist.obj" \
        "$(INTDIR)\odbcapi.obj" \
-       "$(INTDIR)\odbcapi30.obj" \
        "$(INTDIR)\psqlodbc.res"
 
 "$(OUTDIR)\psqlodbc.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
@@ -219,7 +217,6 @@ CLEAN :
        -@erase "$(INTDIR)\tuple.obj"
        -@erase "$(INTDIR)\tuplelist.obj"
        -@erase "$(INTDIR)\odbcapi.obj"
-       -@erase "$(INTDIR)\odbcapi30.obj"
        -@erase "$(INTDIR)\vc60.idb"
        -@erase "$(INTDIR)\vc60.pdb"
        -@erase "$(OUTDIR)\psqlodbc.dll"
@@ -307,7 +304,6 @@ LINK32_OBJS= \
        "$(INTDIR)\tuple.obj" \
        "$(INTDIR)\tuplelist.obj" \
        "$(INTDIR)\odbcapi.obj" \
-       "$(INTDIR)\odbcapi30.obj" \
        "$(INTDIR)\psqlodbc.res"
 
 "$(OUTDIR)\psqlodbc.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
@@ -496,11 +492,6 @@ SOURCE=odbcapi.c
        $(CPP) $(CPP_PROJ) $(SOURCE)
 
 
-SOURCE=odbcapi30.c
-
-"$(INTDIR)\odbcapi30.obj" : $(SOURCE) "$(INTDIR)"
-       $(CPP) $(CPP_PROJ) $(SOURCE)
-
 
 
 !ENDIF