1.Introduce pgtype_attr_xxxx functions which take a typmod parameter as well as a...
authorHiroshi Inoue <inoue@tpf.co.jp>
Sat, 21 Aug 2010 06:29:20 +0000 (06:29 +0000)
committerHiroshi Inoue <inoue@tpf.co.jp>
Sat, 21 Aug 2010 06:29:20 +0000 (06:29 +0000)
2.Call PQconnectdbParams instead of PQconnectdb when it's available.
3.Make cursor open check at transaction end a little more effective.
4.Added code for SQL_INTERVAL support and refcursor support though
  they are disabled.

20 files changed:
bind.c
bind.h
configure.ac
connection.c
convert.c
convert.h
dlg_specific.h
environ.c
environ.h
execute.c
info.c
loadlib.c
loadlib.h
pgtypes.c
pgtypes.h
qresult.c
qresult.h
results.c
statement.c
version.h

diff --git a/bind.c b/bind.c
index 4c29e29623c8a21834463b520494c6b6540f90bc..1939f747dd9847da41a703cb61283bbc474fe34a 100644 (file)
--- a/bind.c
+++ b/bind.c
@@ -96,6 +96,12 @@ PGAPI_BindParameter(
            if (ibScale > 0)
                ipdopts->parameters[ipar].precision = ibScale;
            break;
+       case SQL_C_INTERVAL_DAY_TO_SECOND:
+       case SQL_C_INTERVAL_HOUR_TO_SECOND:
+       case SQL_C_INTERVAL_MINUTE_TO_SECOND:
+       case SQL_C_INTERVAL_SECOND:
+               ipdopts->parameters[ipar].precision = 6;
+           break;
    }
    apdopts->parameters[ipar].precision = ipdopts->parameters[ipar].precision;
    apdopts->parameters[ipar].scale = ipdopts->parameters[ipar].scale;
@@ -265,12 +271,22 @@ inolog("Bind column 0 is type %d not of type SQL_C_BOOKMARK", fCType);
        opts->bindings[icol].used =
        opts->bindings[icol].indicator = pcbValue;
        opts->bindings[icol].returntype = fCType;
+       opts->bindings[icol].precision = 0;
 #if (ODBCVER >= 0x0300)
-       if (SQL_C_NUMERIC == fCType)
-           opts->bindings[icol].precision = 32;
-       else
+       switch (fCType)
+       {
+           case SQL_C_NUMERIC:
+               opts->bindings[icol].precision = 32;
+               break;
+           case SQL_C_TIMESTAMP:
+           case SQL_C_INTERVAL_DAY_TO_SECOND:
+           case SQL_C_INTERVAL_HOUR_TO_SECOND:
+           case SQL_C_INTERVAL_MINUTE_TO_SECOND:
+           case SQL_C_INTERVAL_SECOND:
+               opts->bindings[icol].precision = 6;
+               break;  
+       }
 #endif /* ODBCVER */
-           opts->bindings[icol].precision = 0;
        opts->bindings[icol].scale = 0;
 
        mylog("       bound buffer[%d] = %p\n", icol, opts->bindings[icol].buffer);
@@ -394,7 +410,7 @@ inolog("[%d].SQLType=%d .PGType=%d\n", ipar, ipdopts->parameters[ipar].SQLType,
    }
 
    if (pfNullable)
-       *pfNullable = pgtype_nullable(stmt, ipdopts->parameters[ipar].paramType);
+       *pfNullable = pgtype_nullable(SC_get_conn(stmt), ipdopts->parameters[ipar].paramType);
 cleanup:
 #undef return
    if (stmt->internal)
diff --git a/bind.h b/bind.h
index 9aee864de3cadb38f7ad5f17b77f4fab57df962b..3a2d318c003cd4b5c0bec0c2620dc8d98d7864ad 100644 (file)
--- a/bind.h
+++ b/bind.h
@@ -92,7 +92,7 @@ typedef struct
 /* Macros to handle pgtype of parameters */
 #define    PIC_get_pgtype(pari) ((pari).PGType)
 #define    PIC_set_pgtype(pari, type) ((pari).PGType = (type))
-#define    PIC_dsp_pgtype(stmt, pari) ((pari).PGType ? (pari).PGType : sqltype_to_pgtype(stmt, (pari).SQLType))
+#define    PIC_dsp_pgtype(conn, pari) ((pari).PGType ? (pari).PGType : sqltype_to_pgtype(conn, (pari).SQLType))
 
 void   extend_column_bindings(ARDFields *opts, int num_columns);
 void   reset_a_column_binding(ARDFields *opts, int icol);
index ce516f3ac9fe925b43b59cbf4f34faf83b3ddd0f..09ba60404e23f3c162deab1efa7d08e5e6c4e9b2 100644 (file)
@@ -168,6 +168,28 @@ PGAC_ARG_BOOL(enable, openssl, yes,
 
 AM_CONDITIONAL(enable_openssl, [test x"$enable_openssl" = xyes])
 
+#
+# GSSAPI support
+#
+
+PGAC_ARG_BOOL(enable, gss, no,
+              [  --disable-gss       do not build GSSAPI support],
+              [AC_DEFINE(USE_GSS, 1,
+                         [Define to 1 to build with GSSAPI support (--enable-gss)])])
+
+AM_CONDITIONAL(enable_gss, [test x"$enable_gss" = xyes])
+
+#
+# GKerberos 5 support
+#
+
+PGAC_ARG_BOOL(enable, krb5, no,
+              [  --disable-krb5       do not build Kerberos5 support],
+              [AC_DEFINE(USE_KRB5, 1,
+                         [Define to 1 to build with Kerberos 5 support (--enable-krb5)])])
+
+AM_CONDITIONAL(enable_krb5, [test x"$enable_krb5" = xyes])
+
 #
 # Pthreads
 #
@@ -236,6 +258,14 @@ if test "$enable_openssl" = yes; then
   AC_CHECK_LIB(ssl, SSL_read, [], [AC_MSG_ERROR([ssl library not found])])
 fi
 
+if test "$enable_gss" = yes; then
+  AC_SEARCH_LIBS(gss_init_sec_context, [gssapi_krb5 gss 'gssapi -lkrb5 -lcrypto'], [],  [AC_MSG_ERROR([gssapi library not found])])
+fi
+
+if test "$enable_krb5" = yes; then
+  AC_SEARCH_LIBS(krb5_sendauth, [krb5 'krb5 -lcrypto -ldes -lasn1 -lroken'], [], [AC_MSG_ERROR([krb5 library not found])])
+  AC_SEARCH_LIBS(com_err, [krb5 'krb5 -lcrypto -ldes -lasn1 -lroken' comerr 'comerr -lssl -lcrypto'], [], [AC_MSG_ERROR([comerr library not found])])
+fi
 
 # 3. Header files
 
@@ -246,6 +276,13 @@ fi
 if test "$enable_openssl" = yes; then
   AC_CHECK_HEADER([openssl/ssl.h],,[AC_MSG_ERROR([ssl header not found])])
 fi
+if test "$enable_gss" = yes; then
+  AC_CHECK_HEADERS([gssapi/gssapi.h], [],
+   [AC_CHECK_HEADERS([gssapi.h], [], [AC_MSG_ERROR([gssapi header not found])])])
+fi
+if test "$enable_krb5" = yes; then
+  AC_CHECK_HEADER([krb5.h],,[AC_MSG_ERROR([krb5 header not found])])
+fi
 AC_HEADER_TIME
 
 
@@ -294,6 +331,19 @@ if test "$enable_pthreads" = yes; then
                                             [Define if you have PTHREAD_MUTEX_RECURSIVE_NP])])])
   fi
 fi
+if test "$enable_krb5" = yes; then
+  AC_CHECK_MEMBERS(krb5_error.text.data, [],
+                   [AC_CHECK_MEMBERS(krb5_error.e_data, [],
+                                     [AC_MSG_ERROR([could not determine how to extract Kerberos 5 error messages])],
+                                     [#include <krb5.h>])],
+                   [#include <krb5.h>])
+  AC_MSG_CHECKING(for krb5_free_unparsed_name)
+  AC_TRY_LINK([#include <krb5.h>],
+              [krb5_free_unparsed_name(NULL,NULL);],
+              [AC_DEFINE(HAVE_KRB5_FREE_UNPARSED_NAME, 1, [Define to 1 if you have krb5_free_unparsed_name]) 
+AC_MSG_RESULT(yes)],
+              [AC_MSG_RESULT(no)])
+fi
 
 # 8. Libltdl
 AC_CHECK_LIB(ltdl, lt_dlopen)
index 47eef470d0d2a27899f5acba915376af62dc389b..b13238cfda36d3919c7ea469b60ac1a94d4797ee 100644 (file)
@@ -947,6 +947,7 @@ handle_notice_message(ConnectionClass *self, char *msgbuf, size_t buflen, char *
            while (truncated)
                truncated = SOCK_get_string(sock, msgbuffer, sizeof(msgbuffer));
        }
+mylog("notice message len=%d\n", strlen(msgbuf));
    }
    else
    {
@@ -1033,7 +1034,7 @@ inolog("parameter name=%s\n", msgbuffer);
 inolog("parameter value=%s\n", msgbuffer);
 }
 
-static int protocol3_opts_array(ConnectionClass *self, const char *opts[][2], BOOL libpqopt, int dim_opts)
+static int protocol3_opts_array(ConnectionClass *self, const char *opts[], const char *vals[], BOOL libpqopt, int dim_opts)
 {
    ConnInfo    *ci = &(self->connInfo);
    const   char    *enc = NULL;
@@ -1042,21 +1043,21 @@ static int  protocol3_opts_array(ConnectionClass *self, const char *opts[][2], BO
    cnt = 0;
    if (libpqopt && ci->server[0])
    {
-       opts[cnt][0] = "host";      opts[cnt++][1] = ci->server;
+       opts[cnt] = "host";     vals[cnt++] = ci->server;
    }
    if (libpqopt && ci->port[0])
    {
-       opts[cnt][0] = "port";      opts[cnt++][1] = ci->port;
+       opts[cnt] = "port";     vals[cnt++] = ci->port;
    }
    if (ci->database[0])
    {
        if (libpqopt)
        {
-           opts[cnt][0] = "dbname";    opts[cnt++][1] = ci->database;
+           opts[cnt] = "dbname";   vals[cnt++] = ci->database;
        }
        else
        {
-           opts[cnt][0] = "database";  opts[cnt++][1] = ci->database;
+           opts[cnt] = "database"; vals[cnt++] = ci->database;
        }
    }
    if (ci->username[0] || !libpqopt)
@@ -1066,7 +1067,7 @@ static int    protocol3_opts_array(ConnectionClass *self, const char *opts[][2], BO
        DWORD namesize = sizeof(ci->username) - 2;
 #endif /* WIN32 */
 
-       opts[cnt][0] = "user";
+       opts[cnt] = "user";
        if (!usrname[0])
        {
 #ifdef WIN32
@@ -1075,7 +1076,7 @@ static int    protocol3_opts_array(ConnectionClass *self, const char *opts[][2], BO
 #endif /* WIN32 */
        }
 mylog("!!! usrname=%s server=%s\n", usrname, ci->server);
-       opts[cnt++][1] = usrname;
+       vals[cnt++] = usrname;
    }
    if (libpqopt)
    {
@@ -1084,19 +1085,19 @@ mylog("!!! usrname=%s server=%s\n", usrname, ci->server);
            case '\0':
                break;
            case SSLLBYTE_VERIFY:
-               opts[cnt][0] = "sslmode";
+               opts[cnt] = "sslmode";
                if (ssl_verify_available())
                {
                    switch (ci->sslmode[1])
                    {
                        case 'f':
-                           opts[cnt++][1] = SSLMODE_VERIFY_FULL;
+                           vals[cnt++] = SSLMODE_VERIFY_FULL;
                                break;
                        case 'c':
-                           opts[cnt++][1] = SSLMODE_VERIFY_CA;
+                           vals[cnt++] = SSLMODE_VERIFY_CA;
                                break;
                        default:
-                           opts[cnt++][1] = ci->sslmode;
+                           vals[cnt++] = ci->sslmode;
                    }
                }
                else
@@ -1109,42 +1110,45 @@ mylog("!!! usrname=%s server=%s\n", usrname, ci->server);
                }
                break;
            default:
-               opts[cnt][0] = "sslmode";
-               opts[cnt++][1] = ci->sslmode;
+               opts[cnt] = "sslmode";
+               vals[cnt++] = ci->sslmode;
        }
        if (ci->password[0])
        {
-           opts[cnt][0] = "password";  opts[cnt++][1] = ci->password;
+           opts[cnt] = "password"; vals[cnt++] = ci->password;
        }
        if (ci->gssauth_use_gssapi)
        {
-           opts[cnt][0] = "gsslib";    opts[cnt++][1] = "gssapi";
+           opts[cnt] = "gsslib";   vals[cnt++] = "gssapi";
        }
    }
    else
+   if (connect_with_param_available())
    {
        /* DateStyle */
-       opts[cnt][0] = "DateStyle"; opts[cnt++][1] = "ISO";
+       opts[cnt] = "DateStyle"; vals[cnt++] = "ISO";
        /* extra_float_digits */
-       opts[cnt][0] = "extra_float_digits";    opts[cnt++][1] = "2";
+       opts[cnt] = "extra_float_digits";   vals[cnt++] = "2";
        /* geqo */
-       opts[cnt][0] = "geqo";
+       opts[cnt] = "geqo";
        if (ci->drivers.disable_optimizer)
-           opts[cnt++][1] = "off";
+           vals[cnt++] = "off";
        else
-           opts[cnt++][1] = "on";
+           vals[cnt++] = "on";
        /* client_encoding */
        enc = get_environment_encoding(self, self->original_client_encoding, NULL, TRUE);
        if (enc)
        {
            mylog("startup client_encoding=%s\n", enc);
-           opts[cnt][0] = "client_encoding"; opts[cnt++][1] = enc;
+           opts[cnt] = "client_encoding"; vals[cnt++] = enc;
        }
    }
+   opts[cnt] = vals[cnt] = NULL;
 
    return cnt;
 }
 
+#define    PROTOCOL3_OPTS_MAX  20
 static int protocol3_packet_build(ConnectionClass *self)
 {
    CSTR    func = "protocol3_packet_build";
@@ -1152,18 +1156,18 @@ static int  protocol3_packet_build(ConnectionClass *self)
    size_t  slen;
    char    *packet, *ppacket;
    ProtocolVersion pversion;
-   const   char    *opts[20][2];
+   const   char    *opts[PROTOCOL3_OPTS_MAX], *vals[PROTOCOL3_OPTS_MAX];
    int cnt, i;
 
-   cnt = protocol3_opts_array(self, opts, FALSE, sizeof(opts) / sizeof(opts[0]));
+   cnt = protocol3_opts_array(self, opts, vals, FALSE, sizeof(opts) / sizeof(opts[0]));
    if (cnt < 0)
        return 0;
 
    slen =  sizeof(ProtocolVersion);
    for (i = 0; i < cnt; i++)
    {
-       slen += (strlen(opts[i][0]) + 1);
-       slen += (strlen(opts[i][1]) + 1);
+       slen += (strlen(opts[i]) + 1);
+       slen += (strlen(vals[i]) + 1);
    }
    slen++;
                
@@ -1185,10 +1189,10 @@ static int  protocol3_packet_build(ConnectionClass *self)
    ppacket += sizeof(pversion);
    for (i = 0; i < cnt; i++)
    { 
-       strcpy(ppacket, opts[i][0]);
-       ppacket += (strlen(opts[i][0]) + 1);
-       strcpy(ppacket, opts[i][1]);
-       ppacket += (strlen(opts[i][1]) + 1);
+       strcpy(ppacket, opts[i]);
+       ppacket += (strlen(opts[i]) + 1);
+       strcpy(ppacket, vals[i]);
+       ppacket += (strlen(vals[i]) + 1);
    }
    *ppacket = '\0';
 
@@ -1206,19 +1210,19 @@ static char *protocol3_opts_build(ConnectionClass *self)
    CSTR    func = "protocol3_opts_build";
    size_t  slen;
    char    *conninfo, *ppacket;
-   const   char    *opts[20][2];
+   const   char    *opts[PROTOCOL3_OPTS_MAX], *vals[PROTOCOL3_OPTS_MAX];
    int cnt, i;
    BOOL    blankExist;
 
-   cnt = protocol3_opts_array(self, opts, TRUE, sizeof(opts) / sizeof(opts[0]));
+   cnt = protocol3_opts_array(self, opts, vals, TRUE, sizeof(opts) / sizeof(opts[0]));
    if (cnt < 0)
        return NULL;
 
    slen =  sizeof(ProtocolVersion);
    for (i = 0, slen = 0; i < cnt; i++)
    {
-       slen += (strlen(opts[i][0]) + 2 + 2); /* add 2 bytes for safety (literal quotes) */
-       slen += strlen(opts[i][1]);
+       slen += (strlen(opts[i]) + 2 + 2); /* add 2 bytes for safety (literal quotes) */
+       slen += strlen(vals[i]);
    }
    if (self->login_timeout > 0)
    {
@@ -1240,18 +1244,18 @@ static char *protocol3_opts_build(ConnectionClass *self)
 
    for (i = 0, ppacket = conninfo; i < cnt; i++)
    { 
-       sprintf(ppacket, " %s=", opts[i][0]);
-       ppacket += (strlen(opts[i][0]) + 2);
+       sprintf(ppacket, " %s=", opts[i]);
+       ppacket += (strlen(opts[i]) + 2);
        blankExist = FALSE;
-       if (strchr(opts[i][1], ' '))
+       if (strchr(vals[i], ' '))
            blankExist = TRUE;
        if (blankExist)
        {
            *ppacket = '\'';
            ppacket++;
        }
-       strcpy(ppacket, opts[i][1]);
-       ppacket += strlen(opts[i][1]);
+       strcpy(ppacket, vals[i]);
+       ppacket += strlen(vals[i]);
        if (blankExist)
        {
            *ppacket = '\'';
@@ -2372,20 +2376,45 @@ static void CC_clear_cursors(ConnectionClass *self, BOOL on_abort)
                QResultClass    *wres;
                char    cmd[64];
 
-               snprintf(cmd, sizeof(cmd), "MOVE 0 in \"%s\"", QR_get_cursor(res));
-               CONNLOCK_RELEASE(self);
-               wres = CC_send_query(self, cmd, NULL, ROLLBACK_ON_ERROR | IGNORE_ABORT_ON_CONN, NULL);
-               if (QR_command_maybe_successful(wres))
-                   QR_set_permanent(res);
-               else
-                   QR_set_cursor(res, NULL);
-               QR_Destructor(wres);
-               CONNLOCK_ACQUIRE(self);
+               if (QR_needs_survival_check(res))
+               {
+                   snprintf(cmd, sizeof(cmd), "MOVE 0 in \"%s\"", QR_get_cursor(res));
+                   CONNLOCK_RELEASE(self);
+                   wres = CC_send_query(self, cmd, NULL, ROLLBACK_ON_ERROR | IGNORE_ABORT_ON_CONN, NULL);
+                   QR_set_no_survival_check(res);
+                   if (QR_command_maybe_successful(wres))
+                       QR_set_permanent(res);
+                   else
+                       QR_set_cursor(res, NULL);
+                   QR_Destructor(wres);
+                   CONNLOCK_ACQUIRE(self);
+               }
            }
        }
    }
    CONNLOCK_RELEASE(self);
 }
+
+static void CC_mark_cursors_doubtful(ConnectionClass *self)
+{
+   int i;
+   StatementClass  *stmt;
+   QResultClass    *res;
+
+   if (!self->ncursors)
+       return;
+   CONNLOCK_ACQUIRE(self);
+   for (i = 0; i < self->num_stmts; i++)
+   {
+       stmt = self->stmts[i];
+       if (NULL != stmt &&
+           NULL != (res = SC_get_Result(stmt)) &&
+           NULL != QR_get_cursor(res) &&
+           !QR_is_permanent(res))
+           QR_set_survival_check(res);
+   }
+   CONNLOCK_RELEASE(self);
+}
    
 void   CC_on_commit(ConnectionClass *conn)
 {
@@ -2788,6 +2817,7 @@ inolog("Discarded the first SAVEPOINT\n");
                    }
                    else if (strnicmp(cmdbuffer, rbkcmd, lenrbkcmd) == 0)
                    {
+                       CC_mark_cursors_doubtful(self);
                        if (PROTOCOL_74(&(self->connInfo)))
                            CC_set_in_error_trans(self); /* mark the transaction error in case of manual rollback */
                        else
@@ -3837,14 +3867,24 @@ inolog("sock=%p\n", sock);
        }
    }
 
-   if (!(conninfo = protocol3_opts_build(self)))
+   if (FALSE && connect_with_param_available())
    {
-       if (CC_get_errornumber(self) <= 0)
-           CC_set_error(self, CONN_OPENDB_ERROR, "Couldn't allcate conninfo", func);
-       goto cleanup1;
+       const char *opts[PROTOCOL3_OPTS_MAX], *vals[PROTOCOL3_OPTS_MAX];
+
+       protocol3_opts_array(self, opts, vals, TRUE, sizeof(opts) / sizeof(opts[0]));
+       pqconn = CALL_PQconnectdbParams(opts, vals, &libpqLoaded);
+   }
+   else
+   {
+       if (!(conninfo = protocol3_opts_build(self)))
+       {
+           if (CC_get_errornumber(self) <= 0)
+               CC_set_error(self, CONN_OPENDB_ERROR, "Couldn't allcate conninfo", func);
+           goto cleanup1;
+       }
+       pqconn = CALL_PQconnectdb(conninfo, &libpqLoaded);
+       free(conninfo);
    }
-   pqconn = CALL_PQconnectdb(conninfo, &libpqLoaded);
-   free(conninfo);
    if (!libpqLoaded)
    {
        CC_set_error(self, CONN_UNABLE_TO_LOAD_DLL, "Couldn't load libpq library", func);
index f4c370b100fbc2a3e8c9f113745edf90064b98e4..75ab0724cac06b3323330b7fd76e65e2ff3c722a 100644 (file)
--- a/convert.c
+++ b/convert.c
@@ -400,9 +400,211 @@ stime2timestamp(const SIMPLE_TIME *st, char *str, BOOL bZone, int precision)
    return TRUE;
 }
 
+#if (ODBCVER >= 0x0300)
+static
+SQLINTERVAL    interval2itype(SQLSMALLINT ctype)
+{
+   SQLINTERVAL sqlitv = 0;
+
+   switch (ctype)
+   {
+       case SQL_C_INTERVAL_YEAR:
+           sqlitv = SQL_IS_YEAR;
+           break;
+       case SQL_C_INTERVAL_MONTH:
+           sqlitv = SQL_IS_MONTH;
+           break;
+       case SQL_C_INTERVAL_YEAR_TO_MONTH:
+           sqlitv = SQL_IS_YEAR_TO_MONTH;
+           break;
+       case SQL_C_INTERVAL_DAY:
+           break;
+           sqlitv = SQL_IS_DAY;
+           break;
+       case SQL_C_INTERVAL_HOUR:
+           sqlitv = SQL_IS_HOUR;
+           break;
+       case SQL_C_INTERVAL_DAY_TO_HOUR:
+           sqlitv = SQL_IS_DAY_TO_HOUR;
+           break;
+       case SQL_C_INTERVAL_MINUTE:
+           sqlitv = SQL_IS_MINUTE;
+           break;
+       case SQL_C_INTERVAL_DAY_TO_MINUTE:
+           sqlitv = SQL_IS_DAY_TO_MINUTE;
+           break;
+       case SQL_C_INTERVAL_HOUR_TO_MINUTE:
+           sqlitv = SQL_IS_HOUR_TO_MINUTE;
+           break;
+       case SQL_C_INTERVAL_SECOND:
+           sqlitv = SQL_IS_SECOND;
+           break;
+       case SQL_C_INTERVAL_DAY_TO_SECOND:
+           sqlitv = SQL_IS_DAY_TO_SECOND;
+           break;
+       case SQL_C_INTERVAL_HOUR_TO_SECOND:
+           sqlitv = SQL_IS_HOUR_TO_SECOND;
+           break;
+       case SQL_C_INTERVAL_MINUTE_TO_SECOND:
+           sqlitv = SQL_IS_MINUTE_TO_SECOND;
+           break;
+   }
+   return sqlitv;
+}
+
+/*
+ * Interval data <-----> SQL_INTERVAL_STRUCT
+ */
+
+static int getPrecisionPart(int precision, const char * precPart)
+{
+   char    fraction[] = "000000000";
+   int fracs = sizeof(fraction) - 1, cpys;
+
+   if (precision < 0)
+       precision = 6; /* default */
+   if (precision == 0)
+       return 0;
+   if ((cpys = strlen(precPart)) > fracs)
+       cpys = fracs;
+   memcpy(fraction, precPart, cpys);
+   fraction[precision] = '\0';
+
+   return atoi(fraction);
+}
+
+static BOOL
+interval2istruct(SQLSMALLINT ctype, int precision, const char *str, SQL_INTERVAL_STRUCT *st)
+{
+   char    lit1[64], lit2[64];
+   int scnt, years, mons, days, hours, minutes, seconds;
+   BOOL    sign;
+   SQLINTERVAL itype = interval2itype(ctype);
+
+   memset(st, sizeof(SQL_INTERVAL_STRUCT), 0);
+   if ((scnt = sscanf(str, "%d-%d", &years, &mons)) >=2)
+   {
+       if (SQL_IS_YEAR_TO_MONTH == itype)
+       {
+           sign = years < 0 ? SQL_TRUE : SQL_FALSE;
+           st->interval_type = itype;
+           st->interval_sign = sign;
+           st->intval.year_month.year = sign ? (-years) : years; 
+           st->intval.year_month.month = mons;
+           return TRUE; 
+       }
+       return FALSE;
+   }
+   else if (scnt = sscanf(str, "%d %02d:%02d:%02d.%09s", &days, &hours, &minutes, &seconds, lit2), 5 == scnt || 4 == scnt)
+   {
+       sign = days < 0 ? SQL_TRUE : SQL_FALSE;
+       st->interval_type = itype;
+       st->interval_sign = sign;
+       st->intval.day_second.day = sign ? (-days) : days;
+       st->intval.day_second.hour = hours;
+       st->intval.day_second.minute = minutes;
+       st->intval.day_second.second = seconds;
+       if (scnt > 4)
+           st->intval.day_second.fraction = getPrecisionPart(precision, lit2);
+       return TRUE;
+   }
+   else if ((scnt = sscanf(str, "%d %s %d %s", &years, lit1, &mons, lit2)) >=4)
+   {
+       if (strnicmp(lit1, "year", 4) == 0 &&
+           strnicmp(lit2, "mon", 2) == 0 &&
+           (SQL_IS_MONTH == itype ||
+            SQL_IS_YEAR_TO_MONTH == itype))
+       {
+           sign = years < 0 ? SQL_TRUE : SQL_FALSE;
+           st->interval_type = itype;
+           st->interval_sign = sign;
+           st->intval.year_month.year = sign ? (-years) : years; 
+           st->intval.year_month.month = sign ? (-mons) : mons;
+           return TRUE; 
+       }
+       return FALSE;
+   }
+   if ((scnt = sscanf(str, "%d %s %d", &years, lit1, &days)) == 2)
+   {
+       sign = years < 0 ? SQL_TRUE : SQL_FALSE;
+       if (SQL_IS_YEAR == itype &&
+           (stricmp(lit1, "year") == 0 ||
+            stricmp(lit1, "years") == 0))
+       {
+           st->interval_type = itype;
+           st->interval_sign = sign;
+           st->intval.year_month.year = sign ? (-years) : years; 
+           return TRUE; 
+       }
+       if (SQL_IS_MONTH == itype &&
+           (stricmp(lit1, "mon") == 0 ||
+            stricmp(lit1, "mons") == 0))
+       {
+           st->interval_type = itype;
+           st->interval_sign = sign;
+           st->intval.year_month.month = sign ? (-years) : years; 
+           return TRUE; 
+       }
+       if (SQL_IS_DAY == itype &&
+           (stricmp(lit1, "day") == 0 ||
+            stricmp(lit1, "days") == 0))
+       {
+           st->interval_type = itype;
+           st->interval_sign = sign;
+           st->intval.day_second.day = sign ? (-years) : years; 
+           return TRUE; 
+       }
+       return FALSE;
+   }
+   switch (itype)
+   {
+       case SQL_IS_YEAR:
+       case SQL_IS_MONTH:
+       case SQL_IS_YEAR_TO_MONTH:
+           return FALSE;
+   }
+   scnt = sscanf(str, "%d %s %02d:%02d:%02d.%09s", &days, lit1, &hours, &minutes, &seconds, lit2);
+   if (strnicmp(lit1, "day", 3) != 0)
+       return FALSE;
+   sign = days < 0 ? SQL_TRUE : SQL_FALSE;
+   switch (scnt)
+   {
+       case 5:
+       case 6:
+           st->interval_type = itype;
+           st->interval_sign = sign;
+           st->intval.day_second.day = sign ? (-days) : days;
+           st->intval.day_second.hour = sign ? (-hours) : hours;
+           st->intval.day_second.minute = minutes;
+           st->intval.day_second.second = seconds;
+           if (scnt > 5)
+               st->intval.day_second.fraction = getPrecisionPart(precision, lit2);
+           return TRUE;
+   }
+   scnt = sscanf(str, "%02d:%02d:%02d.%09s", &hours, &minutes, &seconds, lit2);
+   sign = hours < 0 ? SQL_TRUE : SQL_FALSE;
+   switch (scnt)
+   {
+       case 3:
+       case 4:
+           st->interval_type = itype;
+           st->interval_sign = sign;
+           st->intval.day_second.hour = sign ? (-hours) : hours;
+           st->intval.day_second.minute = minutes;
+           st->intval.day_second.second = seconds;
+           if (scnt > 3)
+               st->intval.day_second.fraction = getPrecisionPart(precision, lit2);
+           return TRUE;
+   }
+
+   return FALSE;
+}
+#endif /* ODBCVER */
+
+
 /* This is called by SQLFetch() */
 int
-copy_and_convert_field_bindinfo(StatementClass *stmt, OID field_type, void *value, int col)
+copy_and_convert_field_bindinfo(StatementClass *stmt, OID field_type, int atttypmod, void *value, int col)
 {
    ARDFields *opts = SC_get_ARDF(stmt);
    BindInfoClass *bic;
@@ -412,9 +614,10 @@ copy_and_convert_field_bindinfo(StatementClass *stmt, OID field_type, void *valu
        extend_column_bindings(opts, col + 1);
    bic = &(opts->bindings[col]);
    SC_set_current_col(stmt, -1);
-   return copy_and_convert_field(stmt, field_type, value, bic->returntype,
-           (PTR) (bic->buffer + offset), bic->buflen,
-           LENADDR_SHIFT(bic->used, offset), LENADDR_SHIFT(bic->indicator, offset));
+   return copy_and_convert_field(stmt, field_type, atttypmod, value,
+       bic->returntype, bic->precision,
+       (PTR) (bic->buffer + offset), bic->buflen,
+       LENADDR_SHIFT(bic->used, offset), LENADDR_SHIFT(bic->indicator, offset));
 }
 
 static double get_double_value(const char *str)
@@ -459,9 +662,12 @@ static int char2guid(const char *str, SQLGUID *g)
 
 /* This is called by SQLGetData() */
 int
-copy_and_convert_field(StatementClass *stmt, OID field_type, void *valuei,
-           SQLSMALLINT fCType, PTR rgbValue, SQLLEN cbValueMax,
-           SQLLEN *pcbValue, SQLLEN *pIndicator)
+copy_and_convert_field(StatementClass *stmt,
+       OID field_type, int atttypmod,
+       void *valuei,
+       SQLSMALLINT fCType, int precision,
+       PTR rgbValue, SQLLEN cbValueMax,
+       SQLLEN *pcbValue, SQLLEN *pIndicator)
 {
    CSTR func = "copy_and_convert_field";
    const char *value = valuei;
@@ -483,8 +689,8 @@ copy_and_convert_field(StatementClass *stmt, OID field_type, void *valuei,
    SQLSETPOSIROW       bind_row = stmt->bind_row;
    int         bind_size = opts->bind_size;
    int         result = COPY_OK;
-   ConnectionClass     *conn = SC_get_conn(stmt);
-   BOOL        changed, true_is_minus1 = FALSE;
+   const ConnectionClass   *conn = SC_get_conn(stmt);
+   BOOL        changed;
    BOOL    text_handling, localize_needed;
    const char *neut_str = value;
    char        midtemp[2][32];
@@ -721,6 +927,7 @@ inolog("2stime fr=%d\n", std_time.fr);
        case PG_TYPE_BOOL:
            {                   /* change T/F to 1/0 */
                char       *s;
+               ConnInfo *ci = &(conn->connInfo);
 
                s = midtemp[mtemp_cnt];
                switch (((char *)value)[0])
@@ -733,7 +940,7 @@ inolog("2stime fr=%d\n", std_time.fr);
                        strcpy(s, "0");
                        break;
                    default:
-                       if (true_is_minus1)
+                       if (ci->true_is_minus1)
                            strcpy(s, "-1");
                        else
                            strcpy(s, "1");
@@ -817,7 +1024,7 @@ inolog("2stime fr=%d\n", std_time.fr);
    /* Change default into something useable */
    if (fCType == SQL_C_DEFAULT)
    {
-       fCType = pgtype_to_ctype(stmt, field_type);
+       fCType = pgtype_attr_to_ctype(conn, field_type, atttypmod);
        if (fCType == SQL_C_WCHAR
            && CC_default_is_c(conn))
            fCType = SQL_C_CHAR;
@@ -1609,6 +1816,22 @@ inolog("SQL_C_VARBOOKMARK value=%d\n", ival);
                    *((SQLGUID *) rgbValue + bind_row) = g;
                break;
 #endif /* ODBCVER */
+#if (ODBCVER >= 0x0300)
+           case SQL_C_INTERVAL_YEAR:
+           case SQL_C_INTERVAL_MONTH:
+           case SQL_C_INTERVAL_YEAR_TO_MONTH:
+           case SQL_C_INTERVAL_DAY:
+           case SQL_C_INTERVAL_HOUR:
+           case SQL_C_INTERVAL_DAY_TO_HOUR:
+           case SQL_C_INTERVAL_MINUTE:
+           case SQL_C_INTERVAL_HOUR_TO_MINUTE:
+           case SQL_C_INTERVAL_SECOND:
+           case SQL_C_INTERVAL_DAY_TO_SECOND:
+           case SQL_C_INTERVAL_HOUR_TO_SECOND:
+           case SQL_C_INTERVAL_MINUTE_TO_SECOND:
+               interval2istruct(fCType, precision, neut_str, bind_size > 0 ? (SQL_INTERVAL_STRUCT *) rgbValueBindRow : (SQL_INTERVAL_STRUCT *) rgbValue + bind_row); 
+               break;
+#endif /* ODBCVER */
 
            default:
                qlog("conversion to the type %d isn't supported\n", fCType);
@@ -2364,7 +2587,7 @@ Prepare_and_convert(StatementClass *stmt, QueryParse *qp, QueryBuild *qb)
                if (outpara)
                    CVT_APPEND_STR(qb, "void");
                else
-                   CVT_APPEND_STR(qb, pgtype_to_name(stmt, PIC_dsp_pgtype(stmt, ipdopts->parameters[i]), FALSE));
+                   CVT_APPEND_STR(qb, pgtype_to_name(stmt, PIC_dsp_pgtype(conn, ipdopts->parameters[i]), -1, FALSE));
                oc++;
            }
            CVT_APPEND_CHAR(qb, ')');
@@ -3390,11 +3613,11 @@ inolog("num_p=%d\n", num_p);
                memset(bindreq + leng, 0, sizeof(Int2) * num_p);  /* initialize by text format */
        for (i = stmt->proc_return, j = 0; i < num_params; i++)
        {
-inolog("%dth parameter type oid is %u\n", i, PIC_dsp_pgtype(stmt, parameters[i]));
+inolog("%dth parameter type oid is %u\n", i, PIC_dsp_pgtype(conn, parameters[i]));
            if (discard_output &&
                SQL_PARAM_OUTPUT == parameters[i].paramType)
                continue;
-           if (PG_TYPE_BYTEA == PIC_dsp_pgtype(stmt, parameters[i]))
+           if (PG_TYPE_BYTEA == PIC_dsp_pgtype(conn, parameters[i]))
            {
                mylog("%dth parameter is of binary format\n", j);
                memcpy(bindreq + leng + sizeof(Int2) * j,
@@ -3630,6 +3853,10 @@ ResolveOneParam(QueryBuild *qb, QueryParse *qp)
    BOOL outputDiscard, valueOutput;
    SDOUBLE dbv;
    SFLOAT  flv;
+#if (ODBCVER >= 0x0300)
+   SQL_INTERVAL_STRUCT *ivstruct;
+   const char      *ivsign;
+#endif /* ODBCVER */
 
    outputDiscard = (0 != (qb->flags & FLGB_DISCARD_OUTPUT));
    valueOutput = (0 == (qb->flags & (FLGB_PRE_EXECUTING | FLGB_BUILDING_PREPARE_STATEMENT)));
@@ -3650,6 +3877,7 @@ inolog("resolveOneParam %d(%d,%d)\n", param_number, ipdopts->allocated, apdopts-
        ipara = ipdopts->parameters + param_number;
    if ((!apara || !ipara) && valueOutput)
    {
+mylog("!!! The # of binded parameters (%d, %d) < the # of parameter markers %d\n", apdopts->allocated, ipdopts->allocated, param_number);
        qb->errormsg = "The # of binded parameters < the # of parameter markers";
        qb->errornumber = STMT_COUNT_FIELD_INCORRECT;
        CVT_TERMINATE(qb);  /* just in case */
@@ -3843,7 +4071,7 @@ inolog("ipara=%p paramType=%d %d proc_return=%d\n", ipara, ipara ? ipara->paramT
 
    param_ctype = apara->CType;
    param_sqltype = ipara->SQLType;
-   param_pgtype = PIC_dsp_pgtype(qb->stmt, *ipara);
+   param_pgtype = PIC_dsp_pgtype(qb->conn, *ipara);
 
    mylog("%s: from(fcType)=%d, to(fSqlType)=%d(%u)\n", func,
                param_ctype, param_sqltype, param_pgtype);
@@ -3871,6 +4099,9 @@ inolog("ipara=%p paramType=%d %d proc_return=%d\n", ipara, ipara ? ipara->paramT
    st.d = tim->tm_mday;
    st.y = tim->tm_year + 1900;
 
+#if (ODBCVER >= 0x0300)
+   ivstruct = (SQL_INTERVAL_STRUCT *) buffer;
+#endif /* ODBCVER */
    /* Convert input C type to a neutral format */
    switch (param_ctype)
    {
@@ -4037,6 +4268,49 @@ mylog("C_WCHAR=%s(%d)\n", buffer, used);
        case SQL_C_NUMERIC:
            if (ResolveNumericParam((SQL_NUMERIC_STRUCT *) buffer, param_string))
                break;
+       case SQL_C_INTERVAL_YEAR:
+           ivsign = ivstruct->interval_sign ? "-" : "";
+           sprintf(param_string, "%s%d years", ivsign, ivstruct->intval.year_month.year);
+           break;
+       case SQL_C_INTERVAL_MONTH:
+       case SQL_C_INTERVAL_YEAR_TO_MONTH:
+           ivsign = ivstruct->interval_sign ? "-" : "";
+           sprintf(param_string, "%s%d years %s%d mons", ivsign, ivstruct->intval.year_month.year, ivsign, ivstruct->intval.year_month.month);
+           break;
+       case SQL_C_INTERVAL_DAY:
+           ivsign = ivstruct->interval_sign ? "-" : "";
+           sprintf(param_string, "%s%d days", ivsign, ivstruct->intval.day_second.day);
+           break;
+       case SQL_C_INTERVAL_HOUR:
+       case SQL_C_INTERVAL_DAY_TO_HOUR:
+           ivsign = ivstruct->interval_sign ? "-" : "";
+           sprintf(param_string, "%s%d days %s%02d:00:00", ivsign, ivstruct->intval.day_second.day, ivsign, ivstruct->intval.day_second.hour);
+           break;
+       case SQL_C_INTERVAL_MINUTE:
+       case SQL_C_INTERVAL_HOUR_TO_MINUTE:
+       case SQL_C_INTERVAL_DAY_TO_MINUTE:
+           ivsign = ivstruct->interval_sign ? "-" : "";
+           sprintf(param_string, "%s%d days %s%02d:%02d:00", ivsign, ivstruct->intval.day_second.day, ivsign, ivstruct->intval.day_second.hour, ivstruct->intval.day_second.minute);
+           break;
+
+       case SQL_C_INTERVAL_SECOND:
+       case SQL_C_INTERVAL_DAY_TO_SECOND:
+       case SQL_C_INTERVAL_HOUR_TO_SECOND:
+       case SQL_C_INTERVAL_MINUTE_TO_SECOND:
+           ivsign = ivstruct->interval_sign ? "-" : "";
+           sprintf(param_string, "%s%d days %s%02d:%02d:%02%d", ivsign, ivstruct->intval.day_second.day, ivsign, ivstruct->intval.day_second.hour, ivstruct->intval.day_second.minute, ivstruct->intval.day_second.second);
+           if (ivstruct->intval.day_second.fraction > 0)
+           {
+               int fraction = ivstruct->intval.day_second.fraction, prec = apara->precision;
+               
+               while (fraction % 10 == 0)
+               {
+                   fraction /= 10;
+                   prec--;
+               }
+               sprintf(&param_string[strlen(param_string)], ".%0*d", prec, fraction);
+           }
+           break;
 #endif
 #if (ODBCVER >= 0x0350)
        case SQL_C_GUID:
index 6e2685a8a732d8a6dca811675e083325ea50d086..166763c7d4e0d1c202900df6b83b990dedc447c7 100644 (file)
--- a/convert.h
+++ b/convert.h
@@ -38,10 +38,12 @@ typedef struct
    int         fr;
 } SIMPLE_TIME;
 
-int        copy_and_convert_field_bindinfo(StatementClass *stmt, OID field_type, void *value, int col);
-int    copy_and_convert_field(StatementClass *stmt, OID field_type,
-           void *value, SQLSMALLINT fCType, PTR rgbValue,
-           SQLLEN cbValueMax, SQLLEN *pcbValue, SQLLEN *pIndicator);
+int    copy_and_convert_field_bindinfo(StatementClass *stmt, OID field_type, int atttypmod, void *value, int col);
+int    copy_and_convert_field(StatementClass *stmt,
+           OID field_type, int atttypmod,
+           void *value,
+           SQLSMALLINT fCType, int precision,
+           PTR rgbValue, SQLLEN cbValueMax, SQLLEN *pcbValue, SQLLEN *pIndicator);
 
 int        copy_statement_with_parameters(StatementClass *stmt, BOOL);
 BOOL       convert_money(const char *s, char *sout, size_t soutmax);
index 033b7f785e67880933c0d1d8e1b97e7095329bac..34beaaf938b43693de4cd143ef79f516490b7336 100644 (file)
@@ -25,6 +25,7 @@ extern "C" {
 #define UNKNOWNS_AS_MAX                0
 #define UNKNOWNS_AS_DONTKNOW           1
 #define UNKNOWNS_AS_LONGEST            2
+#define UNKNOWNS_AS_CATALOG            100
 
 /* ODBC initialization files */
 #ifndef WIN32
index 651663e4485dac856baabe2190d285942b6ed447..87e25d0118f1c0d8ba87c9b46a8fabf42b9aa29a 100644 (file)
--- a/environ.c
+++ b/environ.c
@@ -35,11 +35,22 @@ static ConnectionClass **conns = NULL;
 #if defined(WIN_MULTITHREAD_SUPPORT)
 CRITICAL_SECTION   conns_cs;
 CRITICAL_SECTION   common_cs; /* commonly used for short term blocking */
+CRITICAL_SECTION   common_lcs; /* commonly used for not necessarily short term blocking */
 #elif defined(POSIX_MULTITHREAD_SUPPORT)
 pthread_mutex_t     conns_cs;
 pthread_mutex_t     common_cs;
+pthread_mutex_t     common_lcs;
 #endif /* WIN_MULTITHREAD_SUPPORT */
 
+void   shortterm_common_lock()
+{
+   ENTER_COMMON_CS;
+}
+void   shortterm_common_unlock()
+{
+   LEAVE_COMMON_CS;
+}
+
 int    getConnCount()
 {
    return conns_count;
index 24fe6aee23d10973a65e1d61fef62ae77759722f..384a380573431db8e3308f5e90b4670b197b90a6 100644 (file)
--- a/environ.h
+++ b/environ.h
@@ -96,6 +96,8 @@ ConnectionClass * const *getConnList();
 #define DELETE_COMMON_CS
 #endif /* WIN_MULTITHREAD_SUPPORT */
 
+void shortterm_common_lock();
+void shortterm_common_unlock();
 #ifdef __cplusplus
 }
 #endif
index 517c3078b58cafa2e15c62e039335b9be2c6465a..750edf1cd8a6753b16590a8f235a88eec87f1fd2 100644 (file)
--- a/execute.c
+++ b/execute.c
@@ -1646,7 +1646,7 @@ PGAPI_PutData(
            putlen = ctype_length(ctype);
    }
    putbuf = rgbValue;
-   handling_lo = (PIC_dsp_pgtype(stmt, *current_iparam) == conn->lobj_type);
+   handling_lo = (PIC_dsp_pgtype(conn, *current_iparam) == conn->lobj_type);
    if (handling_lo && SQL_C_CHAR == ctype)
    {
        allocbuf = malloc(putlen / 2 + 1);
diff --git a/info.c b/info.c
index 346a4994a213ec4750d1bf1cd48b205bbc20b9c1..a46251321549a0cf4566899779ebd7984aee70fb 100644 (file)
--- a/info.c
+++ b/info.c
@@ -40,7 +40,6 @@
 #include "multibyte.h"
 #include "catfunc.h"
 
-
 /* Trigger related stuff for SQLForeign Keys */
 #define TRIGGER_SHIFT 3
 #define TRIGGER_MASK   0x03
@@ -894,7 +893,7 @@ PGAPI_GetTypeInfo(
 
    for (i = 0, sqlType = sqlTypes[0]; sqlType; sqlType = sqlTypes[++i])
    {
-       pgType = sqltype_to_pgtype(stmt, sqlType);
+       pgType = sqltype_to_pgtype(conn, sqlType);
 
 if (sqlType == SQL_LONGVARBINARY)
 {
@@ -929,19 +928,19 @@ mylog("aunq_match=%d pgtcount=%d\n", aunq_match, pgtcount);
                /* These values can't be NULL */
                if (aunq_match == cnt)
                {
-                   set_tuplefield_string(&tuple[0], pgtype_to_name(stmt, pgType, TRUE));
+                   set_tuplefield_string(&tuple[0], pgtype_to_name(stmt, pgType, PG_UNSPECIFIED, TRUE));
                    set_tuplefield_int2(&tuple[6], SQL_NO_NULLS);
 inolog("serial in\n");
                }
                else
                {
-                   set_tuplefield_string(&tuple[0], pgtype_to_name(stmt, pgType, FALSE));
-                   set_tuplefield_int2(&tuple[6], pgtype_nullable(stmt, pgType));
+                   set_tuplefield_string(&tuple[0], pgtype_to_name(stmt, pgType, PG_UNSPECIFIED, FALSE));
+                   set_tuplefield_int2(&tuple[6], pgtype_nullable(conn, pgType));
                }
                set_tuplefield_int2(&tuple[1], (Int2) sqlType);
-               set_tuplefield_int2(&tuple[7], pgtype_case_sensitive(stmt, pgType));
-               set_tuplefield_int2(&tuple[8], pgtype_searchable(stmt, pgType));
-               set_tuplefield_int2(&tuple[10], pgtype_money(stmt, pgType));
+               set_tuplefield_int2(&tuple[7], pgtype_case_sensitive(conn, pgType));
+               set_tuplefield_int2(&tuple[8], pgtype_searchable(conn, pgType));
+               set_tuplefield_int2(&tuple[10], pgtype_money(conn, pgType));
 
            /*
             * Localized data-source dependent data type name (always
@@ -951,23 +950,23 @@ inolog("serial in\n");
 
                /* These values can be NULL */
                set_nullfield_int4(&tuple[2], pgtype_column_size(stmt, pgType, PG_STATIC, UNKNOWNS_AS_DEFAULT));
-               set_nullfield_string(&tuple[3], pgtype_literal_prefix(stmt, pgType));
-               set_nullfield_string(&tuple[4], pgtype_literal_suffix(stmt, pgType));
-               set_nullfield_string(&tuple[5], pgtype_create_params(stmt, pgType));
+               set_nullfield_string(&tuple[3], pgtype_literal_prefix(conn, pgType));
+               set_nullfield_string(&tuple[4], pgtype_literal_suffix(conn, pgType));
+               set_nullfield_string(&tuple[5], pgtype_create_params(conn, pgType));
                if (1 < pgtcount)
                    set_tuplefield_int2(&tuple[9], SQL_TRUE);
                else
-                   set_nullfield_int2(&tuple[9], pgtype_unsigned(stmt, pgType));
+                   set_nullfield_int2(&tuple[9], pgtype_unsigned(conn, pgType));
                if (aunq_match == cnt)
                    set_tuplefield_int2(&tuple[11], SQL_TRUE);
                else
-                   set_nullfield_int2(&tuple[11], pgtype_auto_increment(stmt, pgType));
-               set_nullfield_int2(&tuple[13], pgtype_min_decimal_digits(stmt, pgType));
-               set_nullfield_int2(&tuple[14], pgtype_max_decimal_digits(stmt, pgType));
+                   set_nullfield_int2(&tuple[11], pgtype_auto_increment(conn, pgType));
+               set_nullfield_int2(&tuple[13], pgtype_min_decimal_digits(conn, pgType));
+               set_nullfield_int2(&tuple[14], pgtype_max_decimal_digits(conn, pgType));
 #if (ODBCVER >=0x0300)
                set_nullfield_int2(&tuple[15], pgtype_to_sqldesctype(stmt, pgType, PG_STATIC));
-               set_nullfield_int2(&tuple[16], pgtype_to_datetime_sub(stmt, pgType));
-               set_nullfield_int4(&tuple[17], pgtype_radix(stmt, pgType));
+               set_nullfield_int2(&tuple[16], pgtype_to_datetime_sub(stmt, pgType, PG_UNSPECIFIED));
+               set_nullfield_int4(&tuple[17], pgtype_radix(conn, pgType));
                set_nullfield_int4(&tuple[18], 0);
 #endif /* ODBCVER */
            }
@@ -2009,15 +2008,16 @@ PGAPI_Columns(
                field_name[MAX_INFO_STRING],
                field_type_name[MAX_INFO_STRING];
    Int2        field_number, sqltype, concise_type,
-               result_cols,
-               decimal_digits;
-   Int4        field_length,
-               mod_length,
-               column_size,
+               result_cols;
+   Int4        mod_length,
                ordinal,
                typmod;
    OID     field_type, the_type, greloid, basetype;
+#ifdef USE_OLD_IMPL
+   Int2        decimal_digits;
+   Int4        field_length, column_size;
    char        useStaticPrecision, useStaticScale;
+#endif /* USE_OLD_IMPL */
    char        not_null[MAX_INFO_STRING],
                relhasrules[MAX_INFO_STRING], relkind[8];
    char    *escSchemaName = NULL, *escTableName = NULL, *escColumnName = NULL;
@@ -2305,7 +2305,11 @@ retry_public_schema:
    result_cols = NUM_OF_COLUMNS_FIELDS;
    extend_column_bindings(SC_get_ARDF(stmt), result_cols);
 
-   stmt->catalog_result = TRUE;
+   /*
+    * Setting catalog_result here affects the behavior of
+    * pgtype_xxx() functions. So set it later.
+    * stmt->catalog_result = TRUE;
+    */
    /* set the field names */
    QR_set_num_fields(res, result_cols);
    QR_set_field_info_v(res, COLUMNS_CATALOG_NAME, "TABLE_QUALIFIER", PG_TYPE_VARCHAR, MAX_INFO_STRING);
@@ -2374,7 +2378,7 @@ retry_public_schema:
            set_tuplefield_int4(&tuple[COLUMNS_PRECISION], pgtype_column_size(stmt, the_type, PG_STATIC, UNKNOWNS_AS_DEFAULT));
            set_tuplefield_int4(&tuple[COLUMNS_LENGTH], pgtype_buffer_length(stmt, the_type, PG_STATIC, UNKNOWNS_AS_DEFAULT));
            set_nullfield_int2(&tuple[COLUMNS_SCALE], pgtype_decimal_digits(stmt, the_type, PG_STATIC));
-           set_nullfield_int2(&tuple[COLUMNS_RADIX], pgtype_radix(stmt, the_type));
+           set_nullfield_int2(&tuple[COLUMNS_RADIX], pgtype_radix(conn, the_type));
            set_tuplefield_int2(&tuple[COLUMNS_NULLABLE], SQL_NO_NULLS);
            set_tuplefield_string(&tuple[COLUMNS_REMARKS], NULL_STRING);
 
@@ -2464,6 +2468,7 @@ mylog(" and the data=%s\n", attdef);
        qlog("%s: table='%s',field_name='%s',type=%d,name='%s'\n",
             func, table_name, field_name, field_type, field_type_name);
 
+#ifdef USE_OLD_IMPL
        useStaticPrecision = TRUE;
        useStaticScale = TRUE;
 
@@ -2535,7 +2540,7 @@ mylog(" and the data=%s\n", attdef);
 #endif /* UNICODE_SUPPORT */
            set_tuplefield_int4(&tuple[COLUMNS_LENGTH], field_length);
 #if (ODBCVER >= 0x0300)
-           set_tuplefield_int4(&tuple[COLUMNS_CHAR_OCTET_LENGTH], pgtype_transfer_octet_length(stmt, field_type, mod_length));
+           set_tuplefield_int4(&tuple[COLUMNS_CHAR_OCTET_LENGTH], pgtype_transfer_octet_length(conn, field_type, mod_length));
 #endif /* ODBCVER */
            set_tuplefield_int4(&tuple[COLUMNS_DISPLAY_SIZE], mod_length);
        }
@@ -2558,15 +2563,36 @@ mylog(" and the data=%s\n", attdef);
 
        if (SQL_TYPE_NULL == sqltype)
        {
-           sqltype = pgtype_to_concise_type(stmt, field_type, PG_STATIC);
-           concise_type = pgtype_to_sqldesctype(stmt, field_type, PG_STATIC);
+           sqltype = pgtype_attr_to_concise_type(conn, field_type, mod_length, -1);
+           concise_type = pgtype_attr_to_sqldesctype(conn, field_type, mod_length);
        }
        else
            concise_type = sqltype;
+#else /* USE_OLD_IMPL */
+       /* Subtract the header length */
+       switch (field_type)
+       {
+           case PG_TYPE_DATETIME:
+           case PG_TYPE_TIMESTAMP_NO_TMZONE:
+           case PG_TYPE_TIME:
+           case PG_TYPE_TIME_WITH_TMZONE:
+               break;
+           default:
+               mod_length -= 4;
+       }
+       set_tuplefield_int4(&tuple[COLUMNS_PRECISION], pgtype_attr_column_size(conn, field_type, mod_length, PG_UNSPECIFIED, UNKNOWNS_AS_DEFAULT));
+       set_tuplefield_int4(&tuple[COLUMNS_LENGTH], pgtype_attr_buffer_length(conn, field_type, mod_length, PG_UNSPECIFIED, UNKNOWNS_AS_DEFAULT));
+       set_tuplefield_int4(&tuple[COLUMNS_DISPLAY_SIZE], pgtype_attr_display_size(conn, field_type, mod_length, PG_UNSPECIFIED, UNKNOWNS_AS_DEFAULT));
+       set_nullfield_int2(&tuple[COLUMNS_SCALE], pgtype_attr_decimal_digits(conn, field_type, mod_length, PG_UNSPECIFIED, UNKNOWNS_AS_DEFAULT));
+
+       sqltype = pgtype_attr_to_concise_type(conn, field_type, mod_length, PG_UNSPECIFIED);
+       concise_type = pgtype_attr_to_sqldesctype(conn, field_type, mod_length);
+#endif /* USE_OLD_IMPL */
+
        set_tuplefield_int2(&tuple[COLUMNS_DATA_TYPE], sqltype);
 
-       set_nullfield_int2(&tuple[COLUMNS_RADIX], pgtype_radix(stmt, field_type));
-       set_tuplefield_int2(&tuple[COLUMNS_NULLABLE], (Int2) (not_null[0] == '1' ? SQL_NO_NULLS : pgtype_nullable(stmt, field_type)));
+       set_nullfield_int2(&tuple[COLUMNS_RADIX], pgtype_radix(conn, field_type));
+       set_tuplefield_int2(&tuple[COLUMNS_NULLABLE], (Int2) (not_null[0] == '1' ? SQL_NO_NULLS : pgtype_nullable(conn, field_type)));
        set_tuplefield_string(&tuple[COLUMNS_REMARKS], NULL_STRING);
 #if (ODBCVER >= 0x0300)
        if (attdef && strlen(attdef) > INFO_VARCHAR_SIZE)
@@ -2574,7 +2600,8 @@ mylog(" and the data=%s\n", attdef);
        else
            set_tuplefield_string(&tuple[COLUMNS_COLUMN_DEF], attdef);
        set_tuplefield_int2(&tuple[COLUMNS_SQL_DATA_TYPE], concise_type);
-       set_nullfield_int2(&tuple[COLUMNS_SQL_DATETIME_SUB], pgtype_to_datetime_sub(stmt, field_type));
+       set_nullfield_int2(&tuple[COLUMNS_SQL_DATETIME_SUB], pgtype_attr_to_datetime_sub(conn, field_type, mod_length));
+       set_tuplefield_int4(&tuple[COLUMNS_CHAR_OCTET_LENGTH], pgtype_attr_transfer_octet_length(conn, field_type, mod_length, UNKNOWNS_AS_DEFAULT));
        set_tuplefield_int4(&tuple[COLUMNS_ORDINAL_POSITION], ordinal);
        set_tuplefield_null(&tuple[COLUMNS_IS_NULLABLE]);
 #endif /* ODBCVER */
@@ -2615,11 +2642,11 @@ mylog(" and the data=%s\n", attdef);
        set_tuplefield_string(&tuple[COLUMNS_COLUMN_NAME], "xmin");
        sqltype = pgtype_to_concise_type(stmt, the_type, PG_STATIC);
        set_tuplefield_int2(&tuple[COLUMNS_DATA_TYPE], sqltype);
-       set_tuplefield_string(&tuple[COLUMNS_TYPE_NAME], pgtype_to_name(stmt, the_type, FALSE));
+       set_tuplefield_string(&tuple[COLUMNS_TYPE_NAME], pgtype_to_name(stmt, the_type, PG_UNSPECIFIED, FALSE));
        set_tuplefield_int4(&tuple[COLUMNS_PRECISION], pgtype_column_size(stmt, the_type, PG_STATIC, UNKNOWNS_AS_DEFAULT));
        set_tuplefield_int4(&tuple[COLUMNS_LENGTH], pgtype_buffer_length(stmt, the_type, PG_STATIC, UNKNOWNS_AS_DEFAULT));
        set_nullfield_int2(&tuple[COLUMNS_SCALE], pgtype_decimal_digits(stmt, the_type, PG_STATIC));
-       set_nullfield_int2(&tuple[COLUMNS_RADIX], pgtype_radix(stmt, the_type));
+       set_nullfield_int2(&tuple[COLUMNS_RADIX], pgtype_radix(conn, the_type));
        set_tuplefield_int2(&tuple[COLUMNS_NULLABLE], SQL_NO_NULLS);
        set_tuplefield_string(&tuple[COLUMNS_REMARKS], NULL_STRING);
 #if (ODBCVER >= 0x0300)
@@ -2647,6 +2674,7 @@ cleanup:
     * results can be retrieved.
     */
    stmt->status = STMT_FINISHED;
+   stmt->catalog_result = TRUE;
 
    /* set up the current tuple pointer for SQLFetch */
    stmt->currTuple = -1;
@@ -2852,7 +2880,7 @@ retry_public_schema:
            set_tuplefield_null(&tuple[0]);
            set_tuplefield_string(&tuple[1], "ctid");
            set_tuplefield_int2(&tuple[2], pgtype_to_concise_type(stmt, the_type, PG_STATIC));
-           set_tuplefield_string(&tuple[3], pgtype_to_name(stmt, the_type, FALSE));
+           set_tuplefield_string(&tuple[3], pgtype_to_name(stmt, the_type, PG_UNSPECIFIED, FALSE));
            set_tuplefield_int4(&tuple[4], pgtype_column_size(stmt, the_type, PG_STATIC, UNKNOWNS_AS_DEFAULT));
            set_tuplefield_int4(&tuple[5], pgtype_buffer_length(stmt, the_type, PG_STATIC, UNKNOWNS_AS_DEFAULT));
            set_tuplefield_int2(&tuple[6], pgtype_decimal_digits(stmt, the_type, PG_STATIC));
@@ -2876,7 +2904,7 @@ inolog("Add ctid\n");
            set_tuplefield_int2(&tuple[0], SQL_SCOPE_SESSION);
            set_tuplefield_string(&tuple[1], OID_NAME);
            set_tuplefield_int2(&tuple[2], pgtype_to_concise_type(stmt, the_type, PG_STATIC));
-           set_tuplefield_string(&tuple[3], pgtype_to_name(stmt, the_type, TRUE));
+           set_tuplefield_string(&tuple[3], pgtype_to_name(stmt, the_type, PG_UNSPECIFIED, TRUE));
            set_tuplefield_int4(&tuple[4], pgtype_column_size(stmt, the_type, PG_STATIC, UNKNOWNS_AS_DEFAULT));
            set_tuplefield_int4(&tuple[5], pgtype_buffer_length(stmt, the_type, PG_STATIC, UNKNOWNS_AS_DEFAULT));
            set_tuplefield_int2(&tuple[6], pgtype_decimal_digits(stmt, the_type, PG_STATIC));
@@ -2893,7 +2921,7 @@ inolog("Add ctid\n");
                set_tuplefield_null(&tuple[0]);
                set_tuplefield_string(&tuple[1], "xmin");
                set_tuplefield_int2(&tuple[2], pgtype_to_concise_type(stmt, the_type, PG_STATIC));
-               set_tuplefield_string(&tuple[3], pgtype_to_name(stmt, the_type, FALSE));
+               set_tuplefield_string(&tuple[3], pgtype_to_name(stmt, the_type, PG_UNSPECIFIED, FALSE));
                set_tuplefield_int4(&tuple[4], pgtype_column_size(stmt, the_type, PG_STATIC, UNKNOWNS_AS_DEFAULT));
                set_tuplefield_int4(&tuple[5], pgtype_buffer_length(stmt, the_type, PG_STATIC, UNKNOWNS_AS_DEFAULT));
                set_tuplefield_int2(&tuple[6], pgtype_decimal_digits(stmt, the_type, PG_STATIC));
@@ -5108,19 +5136,19 @@ mylog("atttypid=%s\n", atttypid ? atttypid : "(null)");
                set_tuplefield_string(&tuple[PROCOLS_COLUMN_NAME], NULL_STRING);
                set_tuplefield_int2(&tuple[PROCOLS_COLUMN_TYPE], SQL_RETURN_VALUE);
                set_tuplefield_int2(&tuple[PROCOLS_DATA_TYPE], pgtype_to_concise_type(stmt, pgtype, PG_STATIC));
-               set_tuplefield_string(&tuple[PROCOLS_TYPE_NAME], pgtype_to_name(stmt, pgtype, FALSE));
+               set_tuplefield_string(&tuple[PROCOLS_TYPE_NAME], pgtype_to_name(stmt, pgtype, PG_UNSPECIFIED, FALSE));
                column_size = pgtype_column_size(stmt, pgtype, PG_STATIC, UNKNOWNS_AS_DEFAULT);
                set_nullfield_int4(&tuple[PROCOLS_COLUMN_SIZE], column_size);
                set_tuplefield_int4(&tuple[PROCOLS_BUFFER_LENGTH], pgtype_buffer_length(stmt, pgtype, PG_STATIC, UNKNOWNS_AS_DEFAULT));
                set_nullfield_int2(&tuple[PROCOLS_DECIMAL_DIGITS], pgtype_decimal_digits(stmt, pgtype, PG_STATIC));
-               set_nullfield_int2(&tuple[PROCOLS_NUM_PREC_RADIX], pgtype_radix(stmt, pgtype));
+               set_nullfield_int2(&tuple[PROCOLS_NUM_PREC_RADIX], pgtype_radix(conn, pgtype));
                set_tuplefield_int2(&tuple[PROCOLS_NULLABLE], SQL_NULLABLE_UNKNOWN);
                set_tuplefield_null(&tuple[PROCOLS_REMARKS]);
 #if (ODBCVER >= 0x0300)
                set_tuplefield_null(&tuple[PROCOLS_COLUMN_DEF]);
                set_nullfield_int2(&tuple[PROCOLS_SQL_DATA_TYPE], pgtype_to_sqldesctype(stmt, pgtype, PG_STATIC));
-               set_nullfield_int2(&tuple[PROCOLS_SQL_DATETIME_SUB], pgtype_to_datetime_sub(stmt, pgtype));
-               set_nullfield_int4(&tuple[PROCOLS_CHAR_OCTET_LENGTH], pgtype_transfer_octet_length(stmt, pgtype, column_size));
+               set_nullfield_int2(&tuple[PROCOLS_SQL_DATETIME_SUB], pgtype_to_datetime_sub(stmt, pgtype, PG_UNSPECIFIED));
+               set_nullfield_int4(&tuple[PROCOLS_CHAR_OCTET_LENGTH], pgtype_attr_transfer_octet_length(conn, pgtype, PG_UNSPECIFIED, UNKNOWNS_AS_DEFAULT));
                set_tuplefield_int4(&tuple[PROCOLS_ORDINAL_POSITION], 0);
                set_tuplefield_string(&tuple[PROCOLS_IS_NULLABLE], NULL_STRING);
 #endif   /* ODBCVER >= 0x0300 */
@@ -5234,19 +5262,19 @@ mylog("atttypid=%s\n", atttypid ? atttypid : "(null)");
                else
                    set_tuplefield_int2(&tuple[PROCOLS_COLUMN_TYPE], SQL_PARAM_INPUT);
                set_tuplefield_int2(&tuple[PROCOLS_DATA_TYPE], pgtype_to_concise_type(stmt, pgtype, PG_STATIC));
-               set_tuplefield_string(&tuple[PROCOLS_TYPE_NAME], pgtype_to_name(stmt, pgtype, FALSE));
+               set_tuplefield_string(&tuple[PROCOLS_TYPE_NAME], pgtype_to_name(stmt, pgtype, PG_UNSPECIFIED, FALSE));
                column_size = pgtype_column_size(stmt, pgtype, PG_STATIC, UNKNOWNS_AS_DEFAULT);
                set_nullfield_int4(&tuple[PROCOLS_COLUMN_SIZE], column_size);
                set_tuplefield_int4(&tuple[PROCOLS_BUFFER_LENGTH], pgtype_buffer_length(stmt, pgtype, PG_STATIC, UNKNOWNS_AS_DEFAULT));
                set_nullfield_int2(&tuple[PROCOLS_DECIMAL_DIGITS], pgtype_decimal_digits(stmt, pgtype, PG_STATIC));
-               set_nullfield_int2(&tuple[PROCOLS_NUM_PREC_RADIX], pgtype_radix(stmt, pgtype));
+               set_nullfield_int2(&tuple[PROCOLS_NUM_PREC_RADIX], pgtype_radix(conn, pgtype));
                set_tuplefield_int2(&tuple[PROCOLS_NULLABLE], SQL_NULLABLE_UNKNOWN);
                set_tuplefield_null(&tuple[PROCOLS_REMARKS]);
 #if (ODBCVER >= 0x0300)
                set_tuplefield_null(&tuple[PROCOLS_COLUMN_DEF]);
                set_nullfield_int2(&tuple[PROCOLS_SQL_DATA_TYPE], pgtype_to_sqldesctype(stmt, pgtype, PG_STATIC));
-               set_nullfield_int2(&tuple[PROCOLS_SQL_DATETIME_SUB], pgtype_to_datetime_sub(stmt, pgtype));
-               set_nullfield_int4(&tuple[PROCOLS_CHAR_OCTET_LENGTH], pgtype_transfer_octet_length(stmt, pgtype, column_size));
+               set_nullfield_int2(&tuple[PROCOLS_SQL_DATETIME_SUB], pgtype_to_datetime_sub(stmt, pgtype, PG_UNSPECIFIED));
+               set_nullfield_int4(&tuple[PROCOLS_CHAR_OCTET_LENGTH], pgtype_attr_transfer_octet_length(conn, pgtype, PG_UNSPECIFIED, UNKNOWNS_AS_DEFAULT));
                set_tuplefield_int4(&tuple[PROCOLS_ORDINAL_POSITION], j + 1);
                set_tuplefield_string(&tuple[PROCOLS_IS_NULLABLE], NULL_STRING);
 #endif   /* ODBCVER >= 0x0300 */
@@ -5274,19 +5302,19 @@ mylog("atttypid=%s\n", atttypid ? atttypid : "(null)");
            set_tuplefield_string(&tuple[PROCOLS_COLUMN_NAME], attname);
            set_tuplefield_int2(&tuple[PROCOLS_COLUMN_TYPE], SQL_RESULT_COL);
            set_tuplefield_int2(&tuple[PROCOLS_DATA_TYPE], pgtype_to_concise_type(stmt, typid, PG_STATIC));
-           set_tuplefield_string(&tuple[PROCOLS_TYPE_NAME], pgtype_to_name(stmt, typid, FALSE));
+           set_tuplefield_string(&tuple[PROCOLS_TYPE_NAME], pgtype_to_name(stmt, typid, PG_UNSPECIFIED, FALSE));
            column_size = pgtype_column_size(stmt, typid, PG_STATIC, UNKNOWNS_AS_DEFAULT);
            set_nullfield_int4(&tuple[PROCOLS_COLUMN_SIZE], column_size);
            set_tuplefield_int4(&tuple[PROCOLS_BUFFER_LENGTH], pgtype_buffer_length(stmt, typid, PG_STATIC, UNKNOWNS_AS_DEFAULT));
            set_nullfield_int2(&tuple[PROCOLS_DECIMAL_DIGITS], pgtype_decimal_digits(stmt, typid, PG_STATIC));
-           set_nullfield_int2(&tuple[PROCOLS_NUM_PREC_RADIX], pgtype_radix(stmt, typid));
+           set_nullfield_int2(&tuple[PROCOLS_NUM_PREC_RADIX], pgtype_radix(conn, typid));
            set_tuplefield_int2(&tuple[PROCOLS_NULLABLE], SQL_NULLABLE_UNKNOWN);
            set_tuplefield_null(&tuple[PROCOLS_REMARKS]);
 #if (ODBCVER >= 0x0300)
            set_tuplefield_null(&tuple[PROCOLS_COLUMN_DEF]);
            set_nullfield_int2(&tuple[PROCOLS_SQL_DATA_TYPE], pgtype_to_sqldesctype(stmt, typid, PG_STATIC));
-           set_nullfield_int2(&tuple[PROCOLS_SQL_DATETIME_SUB], pgtype_to_datetime_sub(stmt, typid));
-           set_nullfield_int4(&tuple[PROCOLS_CHAR_OCTET_LENGTH], pgtype_transfer_octet_length(stmt, typid, column_size));
+           set_nullfield_int2(&tuple[PROCOLS_SQL_DATETIME_SUB], pgtype_to_datetime_sub(stmt, typid, PG_UNSPECIFIED));
+           set_nullfield_int4(&tuple[PROCOLS_CHAR_OCTET_LENGTH], pgtype_attr_transfer_octet_length(conn, typid, PG_UNSPECIFIED, UNKNOWNS_AS_DEFAULT));
            set_tuplefield_int4(&tuple[PROCOLS_ORDINAL_POSITION], 0);
            set_tuplefield_string(&tuple[PROCOLS_IS_NULLABLE], NULL_STRING);
 #endif   /* ODBCVER >= 0x0300 */
index 4d05d93a0468849c3cd45021ef8dd5d0536c04f4..286bccc7d5e7639d875ec6249ede1bdcf7373278 100644 (file)
--- a/loadlib.c
+++ b/loadlib.c
@@ -88,7 +88,9 @@ CSTR  gssapilib = "gssapi64";
 CSTR   gssapilib = "gssapi32";
 #endif /* _WIN64 */
 #ifndef    NOT_USE_LIBPQ
-CSTR   checkproc = "PQconninfoParse";
+CSTR   checkproc1 = "PQconnectdbParams";
+static int connect_withparam_available = -1;
+CSTR   checkproc2 = "PQconninfoParse";
 static int sslverify_available = -1;
 #endif /* NOT_USE_LIBPQ */
 
@@ -156,11 +158,19 @@ DliErrorHook(unsigned dliNotify,
                if (hmodule = MODULE_load_from_psqlodbc_path(libpqlib), NULL == hmodule)
                    hmodule = LoadLibrary(libpqlib);
 #ifndef    NOT_USE_LIBPQ
+               if (NULL == hmodule)
+                   connect_withparam_available = sslverify_available = FALSE;
+               if (connect_withparam_available < 0)
+               {
+                   if (NULL == GetProcAddress(hmodule, checkproc1))
+                       connect_withparam_available = FALSE;
+                   else
+                       connect_withparam_available = TRUE;
+inolog("connect_withparam_available=%d\n", connect_withparam_available); 
+               }
                if (sslverify_available < 0)
                {
-                   if (NULL == hmodule)
-                       sslverify_available = FALSE;
-                   else if (NULL == GetProcAddress(hmodule, checkproc))
+                   if (NULL == GetProcAddress(hmodule, checkproc2))
                        sslverify_available = FALSE;
                    else
                        sslverify_available = TRUE;
@@ -304,7 +314,7 @@ BOOL    ssl_verify_available(void)
        sslverify_available = 1;
        if (NULL != dlhandle)
        {
-           if (NULL == lt_dlsym(dlhandle, checkproc))
+           if (NULL == lt_dlsym(dlhandle, checkproc2))
                sslverify_available = 0;
            lt_dlclose(dlhandle);
        }
@@ -315,6 +325,46 @@ BOOL   ssl_verify_available(void)
    return (0 != sslverify_available);
 }
 
+BOOL   connect_with_param_available(void)
+{
+   if (connect_withparam_available < 0)
+   {
+#if defined(_MSC_DELAY_LOAD_IMPORT)
+       __try {
+#if (_MSC_VER < 1300)
+           __pfnDliFailureHook = DliErrorHook;
+           __pfnDliNotifyHook = DliErrorHook;
+#else
+           __pfnDliFailureHook2 = DliErrorHook;
+           __pfnDliNotifyHook2 = DliErrorHook;
+#endif /* _MSC_VER */
+           PQescapeLiteral(NULL, NULL, 0);
+       }
+       __except (filter_env2encoding(GetExceptionCode())) {
+       }
+       if (connect_withparam_available < 0)
+{
+inolog("connect_withparam_available is set to false\n"); 
+           connect_withparam_available = 0;
+}
+#else
+#ifdef HAVE_LIBLTDL
+       lt_dlhandle dlhandle = lt_dlopenext(libpqlib);
+
+       connect_withparam_available = 1;
+       if (NULL != dlhandle)
+       {
+           if (NULL == lt_dlsym(dlhandle, checkproc1))
+               connect_withparam_available = 0;
+           lt_dlclose(dlhandle);
+       }
+#endif /* HAVE_LIBLTDL */
+#endif /* _MSC_DELAY_LOAD_IMPORT */
+   }
+
+   return (0 != connect_withparam_available);
+}
+
 void *CALL_PQconnectdb(const char *conninfo, BOOL *libpqLoaded)
 {
    void *pqconn = NULL;
@@ -328,6 +378,7 @@ void *CALL_PQconnectdb(const char *conninfo, BOOL *libpqLoaded)
        __pfnDliFailureHook2 = DliErrorHook;
        __pfnDliNotifyHook2 = DliErrorHook;
 #endif /* _MSC_VER */
+inolog("calling PQconnectdb\n");
        pqconn = PQconnectdb(conninfo);
    }
    __except ((GetExceptionCode() & 0xffff) == ERROR_MOD_NOT_FOUND ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
@@ -351,11 +402,53 @@ void *CALL_PQconnectdb(const char *conninfo, BOOL *libpqLoaded)
 #endif /* _MSC_DELAY_LOAD_IMPORT */
    return pqconn;
 }
+
+void *CALL_PQconnectdbParams(const char *opts[], const char *vals[], BOOL *libpqLoaded)
+{
+   void *pqconn = NULL;
+   *libpqLoaded = TRUE;
+#if defined(_MSC_DELAY_LOAD_IMPORT)
+   __try {
+#if (_MSC_VER < 1300)
+       __pfnDliFailureHook = DliErrorHook;
+       __pfnDliNotifyHook = DliErrorHook;
+#else
+       __pfnDliFailureHook2 = DliErrorHook;
+       __pfnDliNotifyHook2 = DliErrorHook;
+#endif /* _MSC_VER */
+inolog("calling PQconnectdbParams\n");
+       pqconn = PQconnectdbParams(opts, vals, 0);
+   }
+   __except ((GetExceptionCode() & 0xffff) == ERROR_MOD_NOT_FOUND ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
+       *libpqLoaded = FALSE;
+   }
+#if (_MSC_VER < 1300)
+   __pfnDliNotifyHook = NULL;
+#else
+   __pfnDliNotifyHook2 = NULL;
+#endif /* _MSC_VER */
+   if (*libpqLoaded)
+   {
+       loaded_libpq = TRUE;
+       /* ssllibs are already loaded by libpq
+       if (PQgetssl(pqconn))
+           loaded_ssllib = TRUE;
+       */
+   }
+#else
+   pqconn = PQconnectdbParams(opts, vals, 0);
+#endif /* _MSC_DELAY_LOAD_IMPORT */
+   return pqconn;
+}
 #else
 BOOL   ssl_verify_available(void)
 {
    return  FALSE;
 }
+BOOL   connect_with_param_available(void)
+{
+   return  FALSE;
+}
 #endif /* NOT_USE_LIBPQ */
 
 #ifdef _HANDLE_ENLIST_IN_DTC_
index 3cfd710dd03dbab70e26d6e2f2ecfe47bacd7792..a1b54551040c457856eb1f1a5714a1459d96e949 100644 (file)
--- a/loadlib.h
+++ b/loadlib.h
@@ -26,8 +26,10 @@ extern "C" {
 BOOL   SSLLIB_check(void);
 #ifndef    NOT_USE_LIBPQ
 void   *CALL_PQconnectdb(const char *conninfo, BOOL *);
+void   *CALL_PQconnectdbParams(const char *opts[], const char *vals[], BOOL *);
 #endif /* NOT_USE_LIBPQ */
 BOOL   ssl_verify_available(void);
+BOOL   connect_with_param_available(void);
 #ifdef _HANDLE_ENLIST_IN_DTC_
 RETCODE    CALL_EnlistInDtc(ConnectionClass *conn, void * pTra, int method);
 RETCODE    CALL_DtcOnDisconnect(ConnectionClass *);
index db2bc59b7e129788b97f2d6d0496ba7bfd35b41e..9601a6cfc407660a34ec007f12a7217e0a3375fd 100644 (file)
--- a/pgtypes.c
+++ b/pgtypes.c
@@ -27,7 +27,7 @@
 #define    EXPERIMENTAL_CURRENTLY
 
 
-Int4       getCharColumnSize(StatementClass *stmt, OID type, int col, int handle_unknown_size_as);
+Int4       getCharColumnSize(const StatementClass *stmt, OID type, int col, int handle_unknown_size_as);
 
 /*
  * these are the types we support. all of the pgtype_ functions should
@@ -110,6 +110,22 @@ SQLSMALLINT    sqlTypes[] = {
 #if (ODBCVER >= 0x0350)
    SQL_GUID,
 #endif /* ODBCVER */
+/* AFAIK SQL_INTERVAL types cause troubles in some spplications */ 
+#ifdef PG_INTERVAL_AS_SQL_INTERVAL
+   SQL_INTERVAL_MONTH,
+   SQL_INTERVAL_YEAR,
+   SQL_INTERVAL_YEAR_TO_MONTH,
+   SQL_INTERVAL_DAY,
+   SQL_INTERVAL_HOUR,
+   SQL_INTERVAL_MINUTE,
+   SQL_INTERVAL_SECOND,
+   SQL_INTERVAL_DAY_TO_HOUR,
+   SQL_INTERVAL_DAY_TO_MINUTE,
+   SQL_INTERVAL_DAY_TO_SECOND,
+   SQL_INTERVAL_HOUR_TO_MINUTE,
+   SQL_INTERVAL_HOUR_TO_SECOND,
+   SQL_INTERVAL_MINUTE_TO_SECOND,
+#endif /* PG_INTERVAL_AS_SQL_INTERVAL */
    0
 };
 
@@ -132,189 +148,404 @@ pg_true_type(const ConnectionClass *conn, OID type, OID basetype)
    return basetype;
 }
 
-OID
-sqltype_to_pgtype(StatementClass *stmt, SQLSMALLINT fSqlType)
-{
-   OID     pgType;
-   ConnectionClass *conn = SC_get_conn(stmt);
-   ConnInfo    *ci = &(conn->connInfo);
+#if    (ODBCVER >= 0x0300)
+#define MONTH_BIT  (1 << 17)
+#define YEAR_BIT   (1 << 18)
+#define DAY_BIT        (1 << 19)
+#define HOUR_BIT   (1 << 26)
+#define MINUTE_BIT (1 << 27)
+#define SECOND_BIT (1 << 28)
 
-   pgType = 0; /* ??? */
-   switch (fSqlType)
+static SQLSMALLINT
+get_interval_type(Int4 atttypmod, const char **name)
+{
+mylog("!!! %s atttypmod=%x\n", __FUNCTION__, atttypmod);
+   if ((-1) == atttypmod)
+       return 0;
+   if (0 != (YEAR_BIT & atttypmod))
    {
-       case SQL_BINARY:
-           pgType = PG_TYPE_BYTEA;
-           break;
-
-       case SQL_CHAR:
-           pgType = PG_TYPE_BPCHAR;
-           break;
-
-#ifdef UNICODE_SUPPORT
-       case SQL_WCHAR:
-           pgType = PG_TYPE_BPCHAR;
-           break;
-#endif /* UNICODE_SUPPORT */
-
-       case SQL_BIT:
-           pgType = ci->drivers.bools_as_char ? PG_TYPE_CHAR : PG_TYPE_BOOL;
-           break;
+       if (0 != (MONTH_BIT & atttypmod))
+       {
+           if (name)
+               *name = "interval year to month";
+           return SQL_INTERVAL_YEAR_TO_MONTH;
+       }
+       if (name)
+           *name = "interval year";
+       return SQL_INTERVAL_YEAR;
+   }
+   else if (0 != (MONTH_BIT & atttypmod))
+   {
+       if (name)
+           *name = "interval month";
+       return SQL_INTERVAL_MONTH;
+   }
+   else if (0 != (DAY_BIT & atttypmod))
+   {
+       if (0 != (SECOND_BIT & atttypmod))
+       {
+           if (name)
+               *name = "interval day to second";
+           return SQL_INTERVAL_DAY_TO_SECOND;
+       }
+       else if (0 != (MINUTE_BIT & atttypmod))
+       {
+           if (name)
+               *name = "interval day to minute";
+           return SQL_INTERVAL_DAY_TO_MINUTE;
+       }
+       else if (0 != (HOUR_BIT & atttypmod))
+       {
+           if (name)
+               *name = "interval day to hour";
+           return SQL_INTERVAL_DAY_TO_HOUR;
+       }
+       if (name)
+           *name = "interval day";
+       return SQL_INTERVAL_DAY;
+   }
+   else if (0 != (HOUR_BIT & atttypmod))
+   {
+       if (0 != (SECOND_BIT & atttypmod))
+       {
+           if (name)
+               *name = "interval hour to second";
+           return SQL_INTERVAL_HOUR_TO_SECOND;
+       }
+       else if (0 != (MINUTE_BIT & atttypmod))
+       {
+           if (name)
+               *name = "interval hour to minute";
+           return SQL_INTERVAL_HOUR_TO_MINUTE;
+       }
+       if (name)
+           *name = "interval hour";
+       return SQL_INTERVAL_HOUR;
+   }
+   else if (0 != (MINUTE_BIT & atttypmod))
+   {
+       if (0 != (SECOND_BIT & atttypmod))
+       {
+           if (name)
+               *name = "interval minute to second";
+           return SQL_INTERVAL_MINUTE_TO_SECOND;
+       }
+       if (name)
+           *name = "interval minute";
+       return SQL_INTERVAL_MINUTE;
+   }
+   else if (0 != (SECOND_BIT & atttypmod))
+   {
+       if (name)
+           *name = "interval second";
+       return SQL_INTERVAL_SECOND;
+   }
 
-#if (ODBCVER >= 0x0300)
-       case SQL_TYPE_DATE:
+   if (name)
+       *name = "interval";
+   return 0;
+}
 #endif /* ODBCVER */
-       case SQL_DATE:
-           pgType = PG_TYPE_DATE;
-           break;
 
-       case SQL_DOUBLE:
-       case SQL_FLOAT:
-           pgType = PG_TYPE_FLOAT8;
-           break;
+static Int4
+getCharColumnSizeX(const ConnectionClass *conn, OID type, int atttypmod, int adtsize_or_longestlen, int handle_unknown_size_as)
+{
+   int     p = -1, maxsize;
+   QResultClass    *result;
+   const ConnInfo  *ci = &(conn->connInfo);
 
-       case SQL_DECIMAL:
-       case SQL_NUMERIC:
-           pgType = PG_TYPE_NUMERIC;
-           break;
+   mylog("%s: type=%d, atttypmod=%d, adtsize_or=%d, unknown = %d\n", __FUNCTION__, type, atttypmod, adtsize_or_longestlen, handle_unknown_size_as);
 
-       case SQL_BIGINT:
-           pgType = PG_TYPE_INT8;
+   /* Assign Maximum size based on parameters */
+   switch (type)
+   {
+       case PG_TYPE_TEXT:
+           if (ci->drivers.text_as_longvarchar)
+               maxsize = ci->drivers.max_longvarchar_size;
+           else
+               maxsize = ci->drivers.max_varchar_size;
            break;
 
-       case SQL_INTEGER:
-           pgType = PG_TYPE_INT4;
+       case PG_TYPE_VARCHAR:
+       case PG_TYPE_BPCHAR:
+           maxsize = ci->drivers.max_varchar_size;
            break;
 
-       case SQL_LONGVARBINARY:
-           if (ci->bytea_as_longvarbinary)
-               pgType = PG_TYPE_BYTEA;
+       default:
+           if (ci->drivers.unknowns_as_longvarchar)
+               maxsize = ci->drivers.max_longvarchar_size;
            else
-               pgType = conn->lobj_type;
-           break;
-
-       case SQL_LONGVARCHAR:
-           pgType = ci->drivers.text_as_longvarchar ? PG_TYPE_TEXT : PG_TYPE_VARCHAR;
+               maxsize = ci->drivers.max_varchar_size;
            break;
-
+   }
 #ifdef UNICODE_SUPPORT
-       case SQL_WLONGVARCHAR:
-           pgType = ci->drivers.text_as_longvarchar ? PG_TYPE_TEXT : PG_TYPE_VARCHAR;
-           break;
+   if (CC_is_in_unicode_driver(conn) &&
+       isSqlServr() &&
+       maxsize > 4000)
+       maxsize = 4000;
 #endif /* UNICODE_SUPPORT */
 
-       case SQL_REAL:
-           pgType = PG_TYPE_FLOAT4;
-           break;
+   if (maxsize == TEXT_FIELD_SIZE + 1) /* magic length for testing */
+   {
+       if (PG_VERSION_GE(conn, 7.1))
+           maxsize = 0;
+       else
+           maxsize = TEXT_FIELD_SIZE;
+   }
+   /*
+    * Static ColumnSize (i.e., the Maximum ColumnSize of the datatype) This
+    * has nothing to do with a result set.
+    */
+inolog("!!! atttypmod  < 0 ?\n");
+   if (atttypmod < 0 && adtsize_or_longestlen < 0)
+       return maxsize;
 
-       case SQL_SMALLINT:
-       case SQL_TINYINT:
-           pgType = PG_TYPE_INT2;
-           break;
+/*
+inolog("!!! Curres == NULL?\n");
+   if (result = SC_get_Curres(stmt), NULL == result)
+       return maxsize;
+*/
 
-       case SQL_TIME:
-#if (ODBCVER >= 0x0300)
-       case SQL_TYPE_TIME:
-#endif /* ODBCVER */
-           pgType = PG_TYPE_TIME;
-           break;
+   /*
+    * Catalog Result Sets -- use assigned column width (i.e., from
+    * set_tuplefield_string)
+    */
+inolog("!!! catalog_result=%d\n", handle_unknown_size_as);
+   if (UNKNOWNS_AS_CATALOG == handle_unknown_size_as)
+   {
+       if (adtsize_or_longestlen > 0)
+           return adtsize_or_longestlen;
+       return maxsize;
+   }
 
-       case SQL_TIMESTAMP:
+inolog("!!! adtsize_or_logngest=%d\n", adtsize_or_longestlen);
+   p = adtsize_or_longestlen; /* longest */
+   /* Size is unknown -- handle according to parameter */
+   if (atttypmod > 0)  /* maybe the length is known */
+   {
+       if (atttypmod >= p)
+           return atttypmod;
+       switch (type)
+       {
+           case PG_TYPE_VARCHAR:
+           case PG_TYPE_BPCHAR:
 #if (ODBCVER >= 0x0300)
-       case SQL_TYPE_TIMESTAMP:
+               return atttypmod;
+#else
+               if (CC_is_in_unicode_driver(conn) || conn->ms_jet)
+                   return atttypmod;
+               return p;
 #endif /* ODBCVER */
-           pgType = PG_TYPE_DATETIME;
-           break;
-
-       case SQL_VARBINARY:
-           pgType = PG_TYPE_BYTEA;
-           break;
-
-       case SQL_VARCHAR:
-           pgType = PG_TYPE_VARCHAR;
-           break;
+       }
+   }
 
-#if    UNICODE_SUPPORT
-       case SQL_WVARCHAR:
-           pgType = PG_TYPE_VARCHAR;
+   /* The type is really unknown */
+   switch (handle_unknown_size_as)
+   {
+       case UNKNOWNS_AS_DONTKNOW:
+           return -1;
+       case UNKNOWNS_AS_LONGEST:
+           mylog("%s: LONGEST: p = %d\n", __FUNCTION__, p);
+           if (p > 0)
+               return p;
            break;
-#endif /* UNICODE_SUPPORT */
-
-#if (ODBCVER >= 0x0350)
-       case SQL_GUID:
-           if (PG_VERSION_GE(conn, 8.3))
-               pgType = PG_TYPE_UUID;
+       case UNKNOWNS_AS_MAX:
            break;
-#endif /* ODBCVER */
-
+       default:
+           return -1;
+   }
+   if (maxsize <= 0)
+       return maxsize;
+   switch (type)
+   {
+       case PG_TYPE_BPCHAR:
+       case PG_TYPE_VARCHAR:
+       case PG_TYPE_TEXT:
+           return maxsize;
    }
 
-   return pgType;
+   if (p > maxsize)
+       maxsize = p;
+   return maxsize;
 }
 
-
-/*
- * There are two ways of calling this function:
- *
- * 1.  When going through the supported PG types (SQLGetTypeInfo)
- *
- * 2.  When taking any type id (SQLColumns, SQLGetData)
- *
- * The first type will always work because all the types defined are returned here.
- * The second type will return a default based on global parameter when it does not
- * know.   This allows for supporting
- * types that are unknown.  All other pg routines in here return a suitable default.
- */
-SQLSMALLINT
-pgtype_to_concise_type(StatementClass *stmt, OID type, int col)
+static SQLSMALLINT
+getNumericDecimalDigitsX(const ConnectionClass *conn, OID type, int atttypmod, int adtsize_or_longest, int handle_unknown_size_as)
 {
-   ConnectionClass *conn = SC_get_conn(stmt);
-   ConnInfo    *ci = &(conn->connInfo);
-#if (ODBCVER >= 0x0300)
-   EnvironmentClass *env = (EnvironmentClass *) CC_get_env(conn);
-#endif /* ODBCVER */
+   Int4        default_decimal_digits = 6;
 
-   switch (type)
-   {
-       case PG_TYPE_CHAR:
-       case PG_TYPE_CHAR2:
-       case PG_TYPE_CHAR4:
-       case PG_TYPE_CHAR8:
-           return ALLOW_WCHAR(conn) ? SQL_WCHAR : SQL_CHAR;
-       case PG_TYPE_NAME:
-           return ALLOW_WCHAR(conn) ? SQL_WVARCHAR : SQL_VARCHAR;
+   mylog("%s: type=%d, atttypmod=%d\n", __FUNCTION__, type, atttypmod);
 
-#ifdef UNICODE_SUPPORT
-       case PG_TYPE_BPCHAR:
-           if (col >= 0 &&
-               getCharColumnSize(stmt, type, col, UNKNOWNS_AS_MAX) > ci->drivers.max_varchar_size)
-               return ALLOW_WCHAR(conn) ? SQL_WLONGVARCHAR : SQL_LONGVARCHAR;
-           return ALLOW_WCHAR(conn) ? SQL_WCHAR : SQL_CHAR;
+   if (atttypmod < 0 && adtsize_or_longest < 0)
+       return default_decimal_digits;
 
-       case PG_TYPE_VARCHAR:
-           if (col >= 0 &&
-               getCharColumnSize(stmt, type, col, UNKNOWNS_AS_MAX) > ci->drivers.max_varchar_size)
-               return ALLOW_WCHAR(conn) ? SQL_WLONGVARCHAR : SQL_LONGVARCHAR;
-           return ALLOW_WCHAR(conn) ? SQL_WVARCHAR : SQL_VARCHAR;
+   if (atttypmod > -1)
+       return (atttypmod & 0xffff);
+   if (adtsize_or_longest <= 0)
+       return default_decimal_digits;
+   if (UNKNOWNS_AS_CATALOG != handle_unknown_size_as)
+   {
+       if (adtsize_or_longest < 5)
+           adtsize_or_longest = 5;
+   }
+   return adtsize_or_longest;
+}
 
-       case PG_TYPE_TEXT:
-           return ci->drivers.text_as_longvarchar ? 
-               (ALLOW_WCHAR(conn) ? SQL_WLONGVARCHAR : SQL_LONGVARCHAR) :
-               (ALLOW_WCHAR(conn) ? SQL_WVARCHAR : SQL_VARCHAR);
+static Int4    /* PostgreSQL restritiction */
+getNumericColumnSizeX(const ConnectionClass *conn, OID type, int atttypmod, int adtsize_or_longest, int handle_unknown_size_as)
+{
+   Int4    default_column_size = 28;
 
-#else
-       case PG_TYPE_BPCHAR:
-           if (col >= 0 &&
-               getCharColumnSize(stmt, type, col, UNKNOWNS_AS_MAX) > ci->drivers.max_varchar_size)
-               return SQL_LONGVARCHAR;
-           return SQL_CHAR;
+   mylog("%s: type=%d, typmod=%d\n", __FUNCTION__, type, atttypmod);
 
-       case PG_TYPE_VARCHAR:
-           if (col >= 0 &&
-               getCharColumnSize(stmt, type, col, UNKNOWNS_AS_MAX) > ci->drivers.max_varchar_size)
-               return SQL_LONGVARCHAR;
-           return SQL_VARCHAR;
+   if (atttypmod < 0 && adtsize_or_longest < 0)
+       return default_column_size;
 
-       case PG_TYPE_TEXT:
+   if (atttypmod > -1)
+       return (atttypmod >> 16) & 0xffff;
+   if (adtsize_or_longest <= 0)
+       return default_column_size;
+   adtsize_or_longest *= 2;
+   if (UNKNOWNS_AS_CATALOG != handle_unknown_size_as)
+   {
+       if (adtsize_or_longest < 10)
+           adtsize_or_longest = 10;
+   }
+   return adtsize_or_longest;
+}
+
+static SQLSMALLINT
+getTimestampDecimalDigitsX(const ConnectionClass *conn, OID type, int atttypmod)
+{
+   mylog("%s: type=%d, atttypmod=%d\n", __FUNCTION__, type, atttypmod);
+
+   if (PG_VERSION_LT(conn, 7.2))
+       return 0;
+
+   return (atttypmod > -1 ? atttypmod : 6);
+}
+
+
+static SQLSMALLINT
+getTimestampColumnSizeX(const ConnectionClass *conn, OID type, int atttypmod)
+{
+   Int4    fixed, scale;
+
+   mylog("%s: type=%d, atttypmod=%d\n", __FUNCTION__, type, atttypmod);
+
+   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:
+           if (USE_ZONE)
+               fixed = 22;
+           else
+               fixed = 19;
+           break;
+   }
+   scale = getTimestampDecimalDigitsX(conn, type, atttypmod);
+   return (scale > 0) ? fixed + 1 + scale : fixed;
+}
+
+static SQLSMALLINT
+getIntervalDecimalDigits(OID type, int atttypmod)
+{
+   Int4    prec;
+
+   mylog("%s: type=%d, atttypmod=%d\n", __FUNCTION__, type, atttypmod);
+
+   if ((atttypmod & SECOND_BIT) == 0)
+       return 0;
+   return (prec = atttypmod & 0xffff) == 0xffff ? 6 : prec ;
+}
+
+static SQLSMALLINT
+getIntervalColumnSize(OID type, int atttypmod)
+{
+   Int4    ttl, leading_precision = 9, scale;
+
+   mylog("%s: type=%d, atttypmod=%d\n", __FUNCTION__, type, atttypmod);
+
+   ttl = leading_precision;
+   switch (get_interval_type(atttypmod, NULL))
+   {
+       case SQL_INTERVAL_DAY_TO_SECOND:
+           ttl += 9;
+           break;
+       case SQL_INTERVAL_HOUR_TO_SECOND:
+       case SQL_INTERVAL_DAY_TO_MINUTE:
+           ttl += 6;
+           break;
+       case SQL_INTERVAL_MINUTE_TO_SECOND:
+       case SQL_INTERVAL_HOUR_TO_MINUTE:
+       case SQL_INTERVAL_DAY_TO_HOUR:
+       case SQL_INTERVAL_YEAR_TO_MONTH:
+           ttl += 3;
+           break;
+   }
+   scale = getIntervalDecimalDigits(type, atttypmod);
+   return (scale > 0) ? ttl + 1 + scale : ttl;
+}
+
+
+SQLSMALLINT
+pgtype_attr_to_concise_type(const ConnectionClass *conn, OID type, int atttypmod, int adtsize_or_longestlen)
+{
+   const ConnInfo  *ci = &(conn->connInfo);
+#if (ODBCVER >= 0x0300)
+   EnvironmentClass *env = (EnvironmentClass *) CC_get_env(conn);
+#ifdef PG_INTERVAL_AS_SQL_INTERVAL
+   SQLSMALLINT sqltype;
+#endif /* PG_INTERVAL_AS_SQL_INTERVAL */
+#endif /* ODBCVER */
+
+   switch (type)
+   {
+       case PG_TYPE_CHAR:
+       case PG_TYPE_CHAR2:
+       case PG_TYPE_CHAR4:
+       case PG_TYPE_CHAR8:
+           return ALLOW_WCHAR(conn) ? SQL_WCHAR : SQL_CHAR;
+       case PG_TYPE_NAME:
+       case PG_TYPE_REFCURSOR:
+           return ALLOW_WCHAR(conn) ? SQL_WVARCHAR : SQL_VARCHAR;
+
+#ifdef UNICODE_SUPPORT
+       case PG_TYPE_BPCHAR:
+           if (getCharColumnSizeX(conn, type, atttypmod, adtsize_or_longestlen, UNKNOWNS_AS_DEFAULT) > ci->drivers.max_varchar_size)
+               return ALLOW_WCHAR(conn) ? SQL_WLONGVARCHAR : SQL_LONGVARCHAR;
+           return ALLOW_WCHAR(conn) ? SQL_WCHAR : SQL_CHAR;
+
+       case PG_TYPE_VARCHAR:
+           if (getCharColumnSizeX(conn, type, atttypmod, adtsize_or_longestlen, UNKNOWNS_AS_DEFAULT) > ci->drivers.max_varchar_size)
+               return ALLOW_WCHAR(conn) ? SQL_WLONGVARCHAR : SQL_LONGVARCHAR;
+           return ALLOW_WCHAR(conn) ? SQL_WVARCHAR : SQL_VARCHAR;
+
+       case PG_TYPE_TEXT:
+           return ci->drivers.text_as_longvarchar ? 
+               (ALLOW_WCHAR(conn) ? SQL_WLONGVARCHAR : SQL_LONGVARCHAR) :
+               (ALLOW_WCHAR(conn) ? SQL_WVARCHAR : SQL_VARCHAR);
+
+#else
+       case PG_TYPE_BPCHAR:
+           if (getCharColumnSizeX(conn, type, atttypmod, adtsize_or_longestlen, UNKNOWNS_AS_DEFAULT) > ci->drivers.max_varchar_size)
+               return SQL_LONGVARCHAR;
+           return SQL_CHAR;
+
+       case PG_TYPE_VARCHAR:
+           if (getCharColumnSizeX(conn, type, atttypmod, adtsize_or_longestlen, UNKNOWNS_AS_DEFAULT) > ci->drivers.max_varchar_size)
+               return SQL_LONGVARCHAR;
+           return SQL_VARCHAR;
+
+       case PG_TYPE_TEXT:
            return ci->drivers.text_as_longvarchar ? SQL_LONGVARCHAR : SQL_VARCHAR;
 #endif /* UNICODE_SUPPORT */
 
@@ -389,6 +620,14 @@ pgtype_to_concise_type(StatementClass *stmt, OID type, int col)
            return SQL_GUID;
 #endif /* ODBCVER */
            return CC_is_in_unicode_driver(conn) ? SQL_WVARCHAR : SQL_VARCHAR;
+
+       case PG_TYPE_INTERVAL:
+#ifdef PG_INTERVAL_AS_SQL_INTERVAL
+           if (sqltype = get_interval_type(atttypmod, NULL), 0 != sqltype)
+               return sqltype;
+#endif /* PG_INTERVAL_AS_SQL_INTERVAL */
+           return CC_is_in_unicode_driver(conn) ? SQL_WVARCHAR : SQL_VARCHAR;
+
        default:
 
            /*
@@ -409,11 +648,15 @@ pgtype_to_concise_type(StatementClass *stmt, OID type, int col)
 }
 
 SQLSMALLINT
-pgtype_to_sqldesctype(StatementClass *stmt, OID type, int col)
+pgtype_attr_to_sqldesctype(const ConnectionClass *conn, OID type, int atttypmod)
 {
    SQLSMALLINT rettype;
 
-   switch (rettype = pgtype_to_concise_type(stmt, type, col))
+#ifdef PG_INTERVAL_AS_SQL_INTERVAL
+   if (PG_TYPE_INTERVAL == type)
+       return SQL_INTERVAL;
+#endif /* PG_INTERVAL_AS_SQL_INTERVAL */
+   switch (rettype = pgtype_attr_to_concise_type(conn, type, atttypmod, PG_UNSPECIFIED))
    {
 #if (ODBCVER >= 0x0300)
        case SQL_TYPE_DATE:
@@ -426,9 +669,11 @@ pgtype_to_sqldesctype(StatementClass *stmt, OID type, int col)
 }
 
 SQLSMALLINT
-pgtype_to_datetime_sub(StatementClass *stmt, OID type)
+pgtype_attr_to_datetime_sub(const ConnectionClass *conn, OID type, int atttypmod)
 {
-   switch (pgtype_to_concise_type(stmt, type, PG_STATIC))
+   SQLSMALLINT rettype;
+
+   switch (rettype = pgtype_attr_to_concise_type(conn, type, atttypmod, PG_UNSPECIFIED))
    {
 #if (ODBCVER >= 0x0300)
        case SQL_TYPE_DATE:
@@ -437,19 +682,34 @@ pgtype_to_datetime_sub(StatementClass *stmt, OID type)
            return SQL_CODE_TIME;
        case SQL_TYPE_TIMESTAMP:
            return SQL_CODE_TIMESTAMP;
+       case SQL_INTERVAL_MONTH:
+       case SQL_INTERVAL_YEAR:
+       case SQL_INTERVAL_YEAR_TO_MONTH:
+       case SQL_INTERVAL_DAY:
+       case SQL_INTERVAL_HOUR:
+       case SQL_INTERVAL_MINUTE:
+       case SQL_INTERVAL_SECOND:
+       case SQL_INTERVAL_DAY_TO_HOUR:
+       case SQL_INTERVAL_DAY_TO_MINUTE:
+       case SQL_INTERVAL_DAY_TO_SECOND:
+       case SQL_INTERVAL_HOUR_TO_MINUTE:
+       case SQL_INTERVAL_HOUR_TO_SECOND:
+       case SQL_INTERVAL_MINUTE_TO_SECOND:
+           return rettype - 100;
 #endif /* ODBCVER */
    }
-   return -1;
+   return rettype;
 }
 
-
 SQLSMALLINT
-pgtype_to_ctype(StatementClass *stmt, OID type)
+pgtype_attr_to_ctype(const ConnectionClass *conn, OID type, int atttypmod)
 {
-   ConnectionClass *conn = SC_get_conn(stmt);
-   ConnInfo    *ci = &(conn->connInfo);
+   const ConnInfo  *ci = &(conn->connInfo);
 #if (ODBCVER >= 0x0300)
    EnvironmentClass *env = (EnvironmentClass *) CC_get_env(conn);
+#ifdef PG_INTERVAL_AS_SQL_INTERVAL
+   SQLSMALLINT ctype;
+#endif /* PG_INTERVAL_A_SQL_INTERVAL */
 #endif /* ODBCVER */
 
    switch (type)
@@ -507,11 +767,7 @@ pgtype_to_ctype(StatementClass *stmt, OID type)
        case PG_TYPE_BPCHAR:
        case PG_TYPE_VARCHAR:
        case PG_TYPE_TEXT:
-           if (CC_is_in_unicode_driver(conn)
-#ifdef NOT_USED
-               && ! stmt->catalog_result
-#endif /* NOT USED */
-               )
+           if (CC_is_in_unicode_driver(conn))
                return SQL_C_WCHAR;
            return SQL_C_CHAR;
 #endif /* UNICODE_SUPPORT */
@@ -520,115 +776,720 @@ pgtype_to_ctype(StatementClass *stmt, OID type)
            if (!conn->ms_jet)
                return SQL_C_GUID;
 #endif /* ODBCVER */
-           return SQL_C_CHAR;
+           return SQL_C_CHAR;
+
+       case PG_TYPE_INTERVAL:
+#ifdef PG_INTERVAL_AS_SQL_INTERVAL
+           if (ctype = get_interval_type(atttypmod, NULL), 0 != ctype)
+               return ctype;
+#endif /* PG_INTERVAL_AS_SQL_INTERVAL */
+           return CC_is_in_unicode_driver(conn) ? SQL_C_WCHAR : SQL_CHAR;
+
+       default:
+           /* hack until permanent type is available */
+           if (type == conn->lobj_type)
+               return SQL_C_BINARY;
+
+           /* Experimental, Does this work ? */
+#ifdef EXPERIMENTAL_CURRENTLY
+           if (ALLOW_WCHAR(conn))
+               return SQL_C_WCHAR;
+#endif /* EXPERIMENTAL_CURRENTLY */
+           return SQL_C_CHAR;
+   }
+}
+
+const char *
+pgtype_attr_to_name(const ConnectionClass *conn, OID type, int atttypmod, BOOL auto_increment)
+{
+   const char  *tname = NULL;
+
+   switch (type)
+   {
+       case PG_TYPE_CHAR:
+           return "char";
+       case PG_TYPE_CHAR2:
+           return "char2";
+       case PG_TYPE_CHAR4:
+           return "char4";
+       case PG_TYPE_CHAR8:
+           return "char8";
+       case PG_TYPE_INT8:
+           return auto_increment ? "bigserial" : "int8";
+       case PG_TYPE_NUMERIC:
+           return "numeric";
+       case PG_TYPE_VARCHAR:
+           return "varchar";
+       case PG_TYPE_BPCHAR:
+           return "char";
+       case PG_TYPE_TEXT:
+           return "text";
+       case PG_TYPE_NAME:
+           return "name";
+       case PG_TYPE_REFCURSOR:
+           return "refcursor";
+       case PG_TYPE_INT2:
+           return "int2";
+       case PG_TYPE_OID:
+           return OID_NAME;
+       case PG_TYPE_XID:
+           return "xid";
+       case PG_TYPE_INT4:
+inolog("pgtype_to_name int4\n");
+           return auto_increment ? "serial" : "int4";
+       case PG_TYPE_FLOAT4:
+           return "float4";
+       case PG_TYPE_FLOAT8:
+           return "float8";
+       case PG_TYPE_DATE:
+           return "date";
+       case PG_TYPE_TIME:
+           return "time";
+       case PG_TYPE_ABSTIME:
+           return "abstime";
+       case PG_TYPE_DATETIME:
+           if (PG_VERSION_GT(conn, 7.1))
+               return "timestamptz";
+           else if (PG_VERSION_LT(conn, 7.0))
+               return "datetime";
+           else
+               return "timestamp";
+       case PG_TYPE_TIMESTAMP_NO_TMZONE:
+           return "timestamp without time zone";
+       case PG_TYPE_TIMESTAMP:
+           return "timestamp";
+       case PG_TYPE_MONEY:
+           return "money";
+       case PG_TYPE_BOOL:
+           return "bool";
+       case PG_TYPE_BYTEA:
+           return "bytea";
+       case PG_TYPE_XML:
+           return "xml";
+       case PG_TYPE_MACADDR:
+           return "macaddr";
+       case PG_TYPE_INET:
+           return "inet";
+       case PG_TYPE_CIDR:
+           return "cidr";
+       case PG_TYPE_UUID:
+           return "uuid";
+#if (ODBCVER >= 0x0300)
+       case PG_TYPE_INTERVAL:
+           get_interval_type(atttypmod, &tname);
+           return tname;
+#endif /* ODBCVER */
+
+       case PG_TYPE_LO_UNDEFINED:
+           return PG_TYPE_LO_NAME;
+
+       default:
+           /* hack until permanent type is available */
+           if (type == conn->lobj_type)
+               return PG_TYPE_LO_NAME;
+
+           /*
+            * "unknown" can actually be used in alter table because it is
+            * a real PG type!
+            */
+           return "unknown";
+   }
+}
+
+
+Int4   /* PostgreSQL restriction */
+pgtype_attr_column_size(const ConnectionClass *conn, OID type, int atttypmod, int adtsize_or_longest, int handle_unknown_size_as)
+{
+   const ConnInfo  *ci = &(conn->connInfo);
+
+   if (handle_unknown_size_as == UNKNOWNS_AS_DEFAULT)
+       handle_unknown_size_as = ci->drivers.unknown_sizes; 
+   switch (type)
+   {
+       case PG_TYPE_CHAR:
+           return 1;
+       case PG_TYPE_CHAR2:
+           return 2;
+       case PG_TYPE_CHAR4:
+           return 4;
+       case PG_TYPE_CHAR8:
+           return 8;
+
+       case PG_TYPE_NAME:
+       case PG_TYPE_REFCURSOR:
+           {
+               int value = 0;
+               if (PG_VERSION_GT(conn, 7.4))
+                   value = CC_get_max_idlen(conn);
+#ifdef NAME_FIELD_SIZE
+               else
+                   value = NAME_FIELD_SIZE;
+#endif /* NAME_FIELD_SIZE */
+               if (0 == value)
+               {
+                   if (PG_VERSION_GE(conn, 7.3))
+                       value = NAMEDATALEN_V73;
+                   else
+                       value = NAMEDATALEN_V72;
+               }
+               return value;
+           }
+
+       case PG_TYPE_INT2:
+           return 5;
+
+       case PG_TYPE_OID:
+       case PG_TYPE_XID:
+       case PG_TYPE_INT4:
+           return 10;
+
+       case PG_TYPE_INT8:
+           return 19;          /* signed */
+
+       case PG_TYPE_NUMERIC:
+           return getNumericColumnSizeX(conn, type, atttypmod, adtsize_or_longest, handle_unknown_size_as); 
+
+       case PG_TYPE_FLOAT4:
+       case PG_TYPE_MONEY:
+           return 7;
+
+       case PG_TYPE_FLOAT8:
+           return 15;
+
+       case PG_TYPE_DATE:
+           return 10;
+       case PG_TYPE_TIME:
+           return 8;
+
+       case PG_TYPE_ABSTIME:
+       case PG_TYPE_TIMESTAMP:
+           return 22;
+       case PG_TYPE_DATETIME:
+       case PG_TYPE_TIMESTAMP_NO_TMZONE:
+           /* return 22; */
+           return getTimestampColumnSizeX(conn, type, atttypmod);
+
+       case PG_TYPE_BOOL:
+           return ci->drivers.bools_as_char ? PG_WIDTH_OF_BOOLS_AS_CHAR : 1;
+
+       case PG_TYPE_MACADDR:
+           return 17;
+
+       case PG_TYPE_INET:
+       case PG_TYPE_CIDR:
+           return sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255/128");
+       case PG_TYPE_UUID:
+           return sizeof("XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX");
+
+       case PG_TYPE_LO_UNDEFINED:
+           return SQL_NO_TOTAL;
+
+       case PG_TYPE_INTERVAL:
+           return getIntervalColumnSize(type, atttypmod);
+
+       default:
+
+           if (type == conn->lobj_type)    /* hack until permanent
+                                                * type is available */
+               return SQL_NO_TOTAL;
+           if (PG_TYPE_BYTEA == type && ci->bytea_as_longvarbinary)
+               return SQL_NO_TOTAL;
+
+           /* Handle Character types and unknown types */
+           return getCharColumnSizeX(conn, type, atttypmod, adtsize_or_longest, handle_unknown_size_as);
+   }
+}
+
+SQLSMALLINT
+pgtype_attr_precision(const ConnectionClass *conn, OID type, int atttypmod, int adtsize_or_longest, int handle_unknown_size_as)
+{
+   switch (type)
+   {
+       case PG_TYPE_NUMERIC:
+           return getNumericColumnSizeX(conn, type, atttypmod, adtsize_or_longest, handle_unknown_size_as);
+       case PG_TYPE_DATETIME:
+       case PG_TYPE_TIMESTAMP_NO_TMZONE:
+           return getTimestampDecimalDigitsX(conn, type, atttypmod);
+#ifdef PG_INTERVAL_AS_SQL_INTERVAL
+       case PG_TYPE_INTERVAL:
+           return getIntervalDecimalDigits(type, atttypmod);
+#endif /* PG_INTERVAL_AS_SQL_INTERVAL */
+   }
+   return -1;
+}
+
+Int4
+pgtype_attr_display_size(const ConnectionClass *conn, OID type, int atttypmod, int adtsize_or_longestlen, int handle_unknown_size_as)
+{
+   int dsize;
+
+   switch (type)
+   {
+       case PG_TYPE_INT2:
+           return 6;
+
+       case PG_TYPE_OID:
+       case PG_TYPE_XID:
+           return 10;
+
+       case PG_TYPE_INT4:
+           return 11;
+
+       case PG_TYPE_INT8:
+           return 20;          /* signed: 19 digits + sign */
+
+       case PG_TYPE_NUMERIC:
+           dsize = getNumericColumnSizeX(conn, type, atttypmod, adtsize_or_longestlen, handle_unknown_size_as);
+           return dsize < 0 ? dsize : dsize + 2;
+
+       case PG_TYPE_MONEY:
+           return 15;          /* ($9,999,999.99) */
+
+       case PG_TYPE_FLOAT4:
+           return 13;
+
+       case PG_TYPE_FLOAT8:
+           return 22;
+
+#if (ODBCVER >= 0x0350)
+       case PG_TYPE_UUID:
+           return 36;
+#endif /* ODBCVER */
+
+       case PG_TYPE_INTERVAL:
+           return 30;
+
+           /* Character types use regular precision */
+       default:
+           return pgtype_attr_column_size(conn, type, atttypmod, adtsize_or_longestlen, handle_unknown_size_as);
+   }
+}
+
+Int4
+pgtype_attr_buffer_length(const ConnectionClass *conn, OID type, int atttypmod, int adtsize_or_longestlen, int handle_unknown_size_as)
+{
+   switch (type)
+   {
+       case PG_TYPE_INT2:
+           return 2; /* sizeof(SQLSMALLINT) */
+
+       case PG_TYPE_OID:
+       case PG_TYPE_XID:
+       case PG_TYPE_INT4:
+           return 4; /* sizeof(SQLINTEGER) */
+
+       case PG_TYPE_INT8:
+           if (SQL_C_CHAR == pgtype_attr_to_ctype(conn, type, atttypmod))
+               return 20;          /* signed: 19 digits + sign */
+           return 8; /* sizeof(SQLSBININT) */
+
+       case PG_TYPE_NUMERIC:
+           return getNumericColumnSizeX(conn, type, atttypmod, adtsize_or_longestlen, handle_unknown_size_as) + 2;
+
+       case PG_TYPE_FLOAT4:
+       case PG_TYPE_MONEY:
+           return 4; /* sizeof(SQLREAL) */
+
+       case PG_TYPE_FLOAT8:
+           return 8; /* sizeof(SQLFLOAT) */
+
+       case PG_TYPE_DATE:
+       case PG_TYPE_TIME:
+           return 6;       /* sizeof(DATE(TIME)_STRUCT) */
+
+       case PG_TYPE_ABSTIME:
+       case PG_TYPE_DATETIME:
+       case PG_TYPE_TIMESTAMP:
+       case PG_TYPE_TIMESTAMP_NO_TMZONE:
+           return 16;      /* sizeof(TIMESTAMP_STRUCT) */
+
+       case PG_TYPE_UUID:
+           return 16;      /* sizeof(SQLGUID) */
+
+           /* Character types use the default precision */
+       case PG_TYPE_VARCHAR:
+       case PG_TYPE_BPCHAR:
+           {
+           int coef = 1;
+           Int4    prec = pgtype_attr_column_size(conn, type, atttypmod, adtsize_or_longestlen, handle_unknown_size_as), maxvarc;
+           if (SQL_NO_TOTAL == prec)
+               return prec;
+#ifdef UNICODE_SUPPORT
+           if (CC_is_in_unicode_driver(conn))
+               return prec * WCLEN;
+#endif /* UNICODE_SUPPORT */
+           /* after 7.2 */
+           if (PG_VERSION_GE(conn, 7.2))
+               coef = conn->mb_maxbyte_per_char;
+           if (coef < 2 && (conn->connInfo).lf_conversion)
+               /* CR -> CR/LF */
+               coef = 2;
+           if (coef == 1)
+               return prec;
+           maxvarc = conn->connInfo.drivers.max_varchar_size;
+           if (prec <= maxvarc && prec * coef > maxvarc)
+               return maxvarc;
+           return coef * prec;
+           }
+#ifdef PG_INTERVAL_AS_SQL_INTERVAL 
+       case PG_TYPE_INTERVAL:
+           return sizeof(SQL_INTERVAL_STRUCT);
+#endif /* PG_INTERVAL_AS_SQL_INTERVAL */ 
+
+       default:
+           return pgtype_attr_column_size(conn, type, atttypmod, adtsize_or_longestlen, handle_unknown_size_as);
+   }
+}
+
+/*
+ */
+Int4
+pgtype_attr_desclength(const ConnectionClass *conn, OID type, int atttypmod, int adtsize_or_longestlen, int handle_unknown_size_as)
+{
+   switch (type)
+   {
+       case PG_TYPE_INT2:
+           return 2;
+
+       case PG_TYPE_OID:
+       case PG_TYPE_XID:
+       case PG_TYPE_INT4:
+           return 4;
+
+       case PG_TYPE_INT8:
+           return 20;          /* signed: 19 digits + sign */
+
+       case PG_TYPE_NUMERIC:
+           return getNumericColumnSizeX(conn, type, atttypmod, adtsize_or_longestlen, handle_unknown_size_as) + 2;
+
+       case PG_TYPE_FLOAT4:
+       case PG_TYPE_MONEY:
+           return 4;
+
+       case PG_TYPE_FLOAT8:
+           return 8;
+
+       case PG_TYPE_DATE:
+       case PG_TYPE_TIME:
+       case PG_TYPE_ABSTIME:
+       case PG_TYPE_DATETIME:
+       case PG_TYPE_TIMESTAMP_NO_TMZONE:
+       case PG_TYPE_TIMESTAMP:
+       case PG_TYPE_VARCHAR:
+       case PG_TYPE_BPCHAR:
+           return pgtype_attr_column_size(conn, type, atttypmod, adtsize_or_longestlen, handle_unknown_size_as);
+       default:
+           return pgtype_attr_column_size(conn, type, atttypmod, adtsize_or_longestlen, handle_unknown_size_as);
+   }
+}
+
+Int2
+pgtype_attr_decimal_digits(const ConnectionClass *conn, OID type, int atttypmod, int adtsize_or_longestlen, int handle_unknown_size_as)
+{
+   switch (type)
+   {
+       case PG_TYPE_INT2:
+       case PG_TYPE_OID:
+       case PG_TYPE_XID:
+       case PG_TYPE_INT4:
+       case PG_TYPE_INT8:
+       case PG_TYPE_FLOAT4:
+       case PG_TYPE_FLOAT8:
+       case PG_TYPE_MONEY:
+       case PG_TYPE_BOOL:
+
+           /*
+            * Number of digits to the right of the decimal point in
+            * "yyyy-mm=dd hh:mm:ss[.f...]"
+            */
+       case PG_TYPE_ABSTIME:
+       case PG_TYPE_TIMESTAMP:
+           return 0;
+       case PG_TYPE_DATETIME:
+       case PG_TYPE_TIMESTAMP_NO_TMZONE:
+           /* return 0; */
+           return getTimestampDecimalDigitsX(conn, type, atttypmod);
+
+       case PG_TYPE_NUMERIC:
+           return getNumericDecimalDigitsX(conn, type, atttypmod, adtsize_or_longestlen, handle_unknown_size_as);
+
+#ifdef PG_INTERVAL_AS_SQL_INTERVAL
+       case PG_TYPE_INTERVAL:
+           return getIntervalDecimalDigits(type, atttypmod);
+#endif /* PG_INTERVAL_AS_SQL_INTERVAL */
+
+       default:
+           return -1;
+   }
+}
+
+Int2
+pgtype_attr_scale(const ConnectionClass *conn, OID type, int atttypmod, int adtsize_or_longestlen, int handle_unknown_size_as)
+{
+   switch (type)
+   {
+       case PG_TYPE_NUMERIC:
+           return getNumericDecimalDigitsX(conn, type, atttypmod, adtsize_or_longestlen, handle_unknown_size_as); 
+   }
+   return -1;
+}
+
+Int4
+pgtype_attr_transfer_octet_length(const ConnectionClass *conn, OID type, int atttypmod, int handle_unknown_size_as)
+{
+   int coef = 1;
+   Int4    maxvarc, column_size;
+   switch (type)
+   {
+       case PG_TYPE_VARCHAR:
+       case PG_TYPE_BPCHAR:
+       case PG_TYPE_TEXT:
+           column_size = pgtype_attr_column_size(conn, type, atttypmod, PG_UNSPECIFIED, handle_unknown_size_as);
+           if (SQL_NO_TOTAL == column_size)
+               return column_size;
+#ifdef UNICODE_SUPPORT
+           if (CC_is_in_unicode_driver(conn))
+               return column_size * WCLEN;
+#endif /* UNICODE_SUPPORT */
+           /* after 7.2 */
+           if (PG_VERSION_GE(conn, 7.2))
+               coef = conn->mb_maxbyte_per_char;
+           if (coef < 2 && (conn->connInfo).lf_conversion)
+               /* CR -> CR/LF */
+               coef = 2;
+           if (coef == 1)
+               return column_size;
+           maxvarc = conn->connInfo.drivers.max_varchar_size;
+           if (column_size <= maxvarc && column_size * coef > maxvarc)
+               return maxvarc;
+           return coef * column_size;
+       case PG_TYPE_BYTEA:
+           return pgtype_attr_column_size(conn, type, atttypmod, PG_UNSPECIFIED, handle_unknown_size_as);
+       default:
+           if (type == conn->lobj_type)
+               return pgtype_attr_column_size(conn, type, atttypmod, PG_UNSPECIFIED, handle_unknown_size_as);
+   }
+   return -1;
+}
+
+
+OID
+sqltype_to_pgtype(const ConnectionClass *conn, SQLSMALLINT fSqlType)
+{
+   OID     pgType;
+   const ConnInfo  *ci = &(conn->connInfo);
+
+   pgType = 0; /* ??? */
+   switch (fSqlType)
+   {
+       case SQL_BINARY:
+           pgType = PG_TYPE_BYTEA;
+           break;
+
+       case SQL_CHAR:
+           pgType = PG_TYPE_BPCHAR;
+           break;
+
+#ifdef UNICODE_SUPPORT
+       case SQL_WCHAR:
+           pgType = PG_TYPE_BPCHAR;
+           break;
+#endif /* UNICODE_SUPPORT */
+
+       case SQL_BIT:
+           pgType = ci->drivers.bools_as_char ? PG_TYPE_CHAR : PG_TYPE_BOOL;
+           break;
+
+#if (ODBCVER >= 0x0300)
+       case SQL_TYPE_DATE:
+#endif /* ODBCVER */
+       case SQL_DATE:
+           pgType = PG_TYPE_DATE;
+           break;
+
+       case SQL_DOUBLE:
+       case SQL_FLOAT:
+           pgType = PG_TYPE_FLOAT8;
+           break;
+
+       case SQL_DECIMAL:
+       case SQL_NUMERIC:
+           pgType = PG_TYPE_NUMERIC;
+           break;
+
+       case SQL_BIGINT:
+           pgType = PG_TYPE_INT8;
+           break;
+
+       case SQL_INTEGER:
+           pgType = PG_TYPE_INT4;
+           break;
+
+       case SQL_LONGVARBINARY:
+           if (ci->bytea_as_longvarbinary)
+               pgType = PG_TYPE_BYTEA;
+           else
+               pgType = conn->lobj_type;
+           break;
+
+       case SQL_LONGVARCHAR:
+           pgType = ci->drivers.text_as_longvarchar ? PG_TYPE_TEXT : PG_TYPE_VARCHAR;
+           break;
+
+#ifdef UNICODE_SUPPORT
+       case SQL_WLONGVARCHAR:
+           pgType = ci->drivers.text_as_longvarchar ? PG_TYPE_TEXT : PG_TYPE_VARCHAR;
+           break;
+#endif /* UNICODE_SUPPORT */
+
+       case SQL_REAL:
+           pgType = PG_TYPE_FLOAT4;
+           break;
+
+       case SQL_SMALLINT:
+       case SQL_TINYINT:
+           pgType = PG_TYPE_INT2;
+           break;
+
+       case SQL_TIME:
+#if (ODBCVER >= 0x0300)
+       case SQL_TYPE_TIME:
+#endif /* ODBCVER */
+           pgType = PG_TYPE_TIME;
+           break;
+
+       case SQL_TIMESTAMP:
+#if (ODBCVER >= 0x0300)
+       case SQL_TYPE_TIMESTAMP:
+#endif /* ODBCVER */
+           pgType = PG_TYPE_DATETIME;
+           break;
+
+       case SQL_VARBINARY:
+           pgType = PG_TYPE_BYTEA;
+           break;
+
+       case SQL_VARCHAR:
+           pgType = PG_TYPE_VARCHAR;
+           break;
+
+#if    UNICODE_SUPPORT
+       case SQL_WVARCHAR:
+           pgType = PG_TYPE_VARCHAR;
+           break;
+#endif /* UNICODE_SUPPORT */
+
+#if (ODBCVER >= 0x0350)
+       case SQL_GUID:
+           if (PG_VERSION_GE(conn, 8.3))
+               pgType = PG_TYPE_UUID;
+           break;
+#endif /* ODBCVER */
 
-       default:
-           /* hack until permanent type is available */
-           if (type == conn->lobj_type)
-               return SQL_C_BINARY;
+       case SQL_INTERVAL_MONTH:
+       case SQL_INTERVAL_YEAR:
+       case SQL_INTERVAL_YEAR_TO_MONTH:
+       case SQL_INTERVAL_DAY:
+       case SQL_INTERVAL_HOUR:
+       case SQL_INTERVAL_MINUTE:
+       case SQL_INTERVAL_SECOND:
+       case SQL_INTERVAL_DAY_TO_HOUR:
+       case SQL_INTERVAL_DAY_TO_MINUTE:
+       case SQL_INTERVAL_DAY_TO_SECOND:
+       case SQL_INTERVAL_HOUR_TO_MINUTE:
+       case SQL_INTERVAL_HOUR_TO_SECOND:
+       case SQL_INTERVAL_MINUTE_TO_SECOND:
+           pgType = PG_TYPE_INTERVAL;
+           break;
+   }
 
-           /* Experimental, Does this work ? */
-#ifdef EXPERIMENTAL_CURRENTLY
-           if (ALLOW_WCHAR(conn))
-               return SQL_C_WCHAR;
-#endif /* EXPERIMENTAL_CURRENTLY */
-           return SQL_C_CHAR;
+   return pgType;
+}
+
+static int
+getAtttypmodEtc(const StatementClass *stmt, int col, int *adtsize_or_longestlen)
+{
+   int atttypmod = -1;
+
+   if (NULL != adtsize_or_longestlen)
+       *adtsize_or_longestlen = -1;
+   if (col >= 0)
+   {
+       const QResultClass  *res;
+
+       if (res = SC_get_Curres(stmt), NULL != res)
+       {
+           atttypmod = QR_get_atttypmod(res, col);
+           if (NULL != adtsize_or_longestlen)
+           {
+               if (stmt->catalog_result)
+                   *adtsize_or_longestlen = QR_get_fieldsize(res, col);
+               else
+                   *adtsize_or_longestlen = QR_get_display_size(res, col);
+           } 
+       }
    }
+   return atttypmod;
 }
 
+/*
+ * There are two ways of calling this function:
+ *
+ * 1.  When going through the supported PG types (SQLGetTypeInfo)
+ *
+ * 2.  When taking any type id (SQLColumns, SQLGetData)
+ *
+ * The first type will always work because all the types defined are returned here.
+ * The second type will return a default based on global parameter when it does not
+ * know.   This allows for supporting
+ * types that are unknown.  All other pg routines in here return a suitable default.
+ */
+SQLSMALLINT
+pgtype_to_concise_type(const StatementClass *stmt, OID type, int col)
+{
+   int atttypmod, adtsize_or_longestlen;
+
+   atttypmod = getAtttypmodEtc(stmt, col, &adtsize_or_longestlen);
+   return pgtype_attr_to_concise_type(SC_get_conn(stmt), type, atttypmod, adtsize_or_longestlen); 
+}
 
-const char *
-pgtype_to_name(StatementClass *stmt, OID type, BOOL auto_increment)
+SQLSMALLINT
+pgtype_to_sqldesctype(const StatementClass *stmt, OID type, int col)
 {
-   ConnectionClass *conn = SC_get_conn(stmt);
-   switch (type)
-   {
-       case PG_TYPE_CHAR:
-           return "char";
-       case PG_TYPE_CHAR2:
-           return "char2";
-       case PG_TYPE_CHAR4:
-           return "char4";
-       case PG_TYPE_CHAR8:
-           return "char8";
-       case PG_TYPE_INT8:
-           return auto_increment ? "bigserial" : "int8";
-       case PG_TYPE_NUMERIC:
-           return "numeric";
-       case PG_TYPE_VARCHAR:
-           return "varchar";
-       case PG_TYPE_BPCHAR:
-           return "char";
-       case PG_TYPE_TEXT:
-           return "text";
-       case PG_TYPE_NAME:
-           return "name";
-       case PG_TYPE_INT2:
-           return "int2";
-       case PG_TYPE_OID:
-           return OID_NAME;
-       case PG_TYPE_XID:
-           return "xid";
-       case PG_TYPE_INT4:
-inolog("pgtype_to_name int4\n");
-           return auto_increment ? "serial" : "int4";
-       case PG_TYPE_FLOAT4:
-           return "float4";
-       case PG_TYPE_FLOAT8:
-           return "float8";
-       case PG_TYPE_DATE:
-           return "date";
-       case PG_TYPE_TIME:
-           return "time";
-       case PG_TYPE_ABSTIME:
-           return "abstime";
-       case PG_TYPE_DATETIME:
-           if (PG_VERSION_GT(conn, 7.1))
-               return "timestamptz";
-           else if (PG_VERSION_LT(conn, 7.0))
-               return "datetime";
-           else
-               return "timestamp";
-       case PG_TYPE_TIMESTAMP_NO_TMZONE:
-           return "timestamp without time zone";
-       case PG_TYPE_TIMESTAMP:
-           return "timestamp";
-       case PG_TYPE_MONEY:
-           return "money";
-       case PG_TYPE_BOOL:
-           return "bool";
-       case PG_TYPE_BYTEA:
-           return "bytea";
-       case PG_TYPE_XML:
-           return "xml";
-       case PG_TYPE_MACADDR:
-           return "macaddr";
-       case PG_TYPE_INET:
-           return "inet";
-       case PG_TYPE_CIDR:
-           return "cidr";
-       case PG_TYPE_UUID:
-           return "uuid";
+   int atttypmod = getAtttypmodEtc(stmt, col, NULL);
 
-       case PG_TYPE_LO_UNDEFINED:
-           return PG_TYPE_LO_NAME;
+   return pgtype_attr_to_sqldesctype(SC_get_conn(stmt), type, atttypmod); 
+}
 
-       default:
-           /* hack until permanent type is available */
-           if (type == conn->lobj_type)
-               return PG_TYPE_LO_NAME;
+SQLSMALLINT
+pgtype_to_datetime_sub(const StatementClass *stmt, OID type, int col)
+{
+   int atttypmod = getAtttypmodEtc(stmt, col, NULL);
 
-           /*
-            * "unknown" can actually be used in alter table because it is
-            * a real PG type!
-            */
-           return "unknown";
-   }
+   return pgtype_attr_to_datetime_sub(SC_get_conn(stmt), type, atttypmod); 
+}
+
+
+SQLSMALLINT
+pgtype_to_ctype(const StatementClass *stmt, OID type, int col)
+{
+   int atttypmod = getAtttypmodEtc(stmt, col, NULL);
+
+   return pgtype_attr_to_ctype(SC_get_conn(stmt), type, atttypmod); 
 }
 
+const char *
+pgtype_to_name(const StatementClass *stmt, OID type, int col, BOOL auto_increment)
+{
+   int atttypmod = getAtttypmodEtc(stmt, col, NULL);
+
+   return pgtype_attr_to_name(SC_get_conn(stmt), type, atttypmod, auto_increment); 
+}
 
+
+#ifdef NOT_USED
 static SQLSMALLINT
-getNumericDecimalDigits(StatementClass *stmt, OID type, int col)
+getNumericDecimalDigits(const StatementClass *stmt, OID type, int col)
 {
    Int4        atttypmod = -1, default_decimal_digits = 6;
    QResultClass    *result;
@@ -672,7 +1533,7 @@ getNumericDecimalDigits(StatementClass *stmt, OID type, int col)
 
 
 static Int4    /* PostgreSQL restritiction */
-getNumericColumnSize(StatementClass *stmt, OID type, int col)
+getNumericColumnSize(const StatementClass *stmt, OID type, int col)
 {
    Int4    atttypmod = -1, default_column_size = 28;
    QResultClass *result;
@@ -715,9 +1576,8 @@ getNumericColumnSize(StatementClass *stmt, OID type, int col)
    }
 }
 
-
 Int4
-getCharColumnSize(StatementClass *stmt, OID type, int col, int handle_unknown_size_as)
+getCharColumnSize(const StatementClass *stmt, OID type, int col, int handle_unknown_size_as)
 {
    CSTR    func = "getCharColumnSize";
    int     p = -1, attlen = -1, adtsize = -1, maxsize;
@@ -836,227 +1696,97 @@ getCharColumnSize(StatementClass *stmt, OID type, int col, int handle_unknown_si
    return maxsize;
 }
 
-static SQLSMALLINT
-getTimestampDecimalDigits(StatementClass *stmt, OID type, int col)
-{
-   ConnectionClass *conn = SC_get_conn(stmt);
-   Int4        atttypmod;
-   QResultClass *result;
-
-   mylog("getTimestampDecimalDigits: type=%d, col=%d\n", type, col);
-
-   if (col < 0)
-       return 0;
-   if (PG_VERSION_LT(conn, 7.2))
-       return 0;
-
-   result = SC_get_Curres(stmt);
-
-   atttypmod = QR_get_atttypmod(result, col);
-   mylog("atttypmod2=%d\n", atttypmod);
-   return (atttypmod > -1 ? atttypmod : 6);
-}
-
-
-static SQLSMALLINT
-getTimestampColumnSize(StatementClass *stmt, OID type, int col)
-{
-   Int4        fixed,
-               scale;
-
-   mylog("getTimestampColumnSize: 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:
-           if (USE_ZONE)
-               fixed = 22;
-           else
-               fixed = 19;
-           break;
-   }
-   scale = getTimestampDecimalDigits(stmt, type, col);
-   return (scale > 0) ? fixed + 1 + scale : fixed;
-}
-
-/*
- * This corresponds to "precision" in ODBC 2.x.
- *
- * For PG_TYPE_VARCHAR, PG_TYPE_BPCHAR, PG_TYPE_NUMERIC, SQLColumns will
- * override this length with the atttypmod length from pg_attribute .
- *
- * If col >= 0, then will attempt to get the info from the result set.
- * This is used for functions SQLDescribeCol and SQLColAttributes.
- */
-Int4   /* PostgreSQL restriction */
-pgtype_column_size(StatementClass *stmt, OID type, int col, int handle_unknown_size_as)
-{
-   ConnectionClass *conn = SC_get_conn(stmt);
-   ConnInfo    *ci = &(conn->connInfo);
-
-   if (handle_unknown_size_as == UNKNOWNS_AS_DEFAULT)
-       handle_unknown_size_as = ci->drivers.unknown_sizes; 
-   switch (type)
-   {
-       case PG_TYPE_CHAR:
-           return 1;
-       case PG_TYPE_CHAR2:
-           return 2;
-       case PG_TYPE_CHAR4:
-           return 4;
-       case PG_TYPE_CHAR8:
-           return 8;
-
-       case PG_TYPE_NAME:
-           {
-               int value = 0;
-               if (PG_VERSION_GT(conn, 7.4))
-                   value = CC_get_max_idlen(conn);
-#ifdef NAME_FIELD_SIZE
-               else
-                   value = NAME_FIELD_SIZE;
-#endif /* NAME_FIELD_SIZE */
-               if (0 == value)
-               {
-                   if (PG_VERSION_GE(conn, 7.3))
-                       value = NAMEDATALEN_V73;
-                   else
-                       value = NAMEDATALEN_V72;
-               }
-               return value;
-           }
-
-       case PG_TYPE_INT2:
-           return 5;
-
-       case PG_TYPE_OID:
-       case PG_TYPE_XID:
-       case PG_TYPE_INT4:
-           return 10;
-
-       case PG_TYPE_INT8:
-           return 19;          /* signed */
-
-       case PG_TYPE_NUMERIC:
-           return getNumericColumnSize(stmt, type, col);
-
-       case PG_TYPE_FLOAT4:
-       case PG_TYPE_MONEY:
-           return 7;
-
-       case PG_TYPE_FLOAT8:
-           return 15;
+static SQLSMALLINT
+getTimestampDecimalDigits(const StatementClass *stmt, OID type, int col)
+{
+   ConnectionClass *conn = SC_get_conn(stmt);
+   Int4        atttypmod;
+   QResultClass *result;
 
-       case PG_TYPE_DATE:
-           return 10;
-       case PG_TYPE_TIME:
-           return 8;
+   mylog("getTimestampDecimalDigits: type=%d, col=%d\n", type, col);
 
-       case PG_TYPE_ABSTIME:
-       case PG_TYPE_TIMESTAMP:
-           return 22;
-       case PG_TYPE_DATETIME:
-       case PG_TYPE_TIMESTAMP_NO_TMZONE:
-           /* return 22; */
-           return getTimestampColumnSize(stmt, type, col);
+   if (col < 0)
+       return 0;
+   if (PG_VERSION_LT(conn, 7.2))
+       return 0;
 
-       case PG_TYPE_BOOL:
-           return ci->drivers.bools_as_char ? PG_WIDTH_OF_BOOLS_AS_CHAR : 1;
+   result = SC_get_Curres(stmt);
 
-       case PG_TYPE_MACADDR:
-           return 17;
+   atttypmod = QR_get_atttypmod(result, col);
+   mylog("atttypmod2=%d\n", atttypmod);
+   return (atttypmod > -1 ? atttypmod : 6);
+}
 
-       case PG_TYPE_INET:
-       case PG_TYPE_CIDR:
-           return sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255/128");
-       case PG_TYPE_UUID:
-           return sizeof("XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX");
 
-       case PG_TYPE_LO_UNDEFINED:
-           return SQL_NO_TOTAL;
+static SQLSMALLINT
+getTimestampColumnSize(const StatementClass *stmt, OID type, int col)
+{
+   Int4        fixed,
+               scale;
+
+   mylog("getTimestampColumnSize: 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:
+           if (USE_ZONE)
+               fixed = 22;
+           else
+               fixed = 19;
+           break;
+   }
+   scale = getTimestampDecimalDigits(stmt, type, col);
+   return (scale > 0) ? fixed + 1 + scale : fixed;
+}
+#endif /* NOT_USED */
 
-           if (type == conn->lobj_type)    /* hack until permanent
-                                                * type is available */
-               return SQL_NO_TOTAL;
-           if (PG_TYPE_BYTEA == type && ci->bytea_as_longvarbinary)
-               return SQL_NO_TOTAL;
+/*
+ * This corresponds to "precision" in ODBC 2.x.
+ *
+ * For PG_TYPE_VARCHAR, PG_TYPE_BPCHAR, PG_TYPE_NUMERIC, SQLColumns will
+ * override this length with the atttypmod length from pg_attribute .
+ *
+ * If col >= 0, then will attempt to get the info from the result set.
+ * This is used for functions SQLDescribeCol and SQLColAttributes.
+ */
+Int4   /* PostgreSQL restriction */
+pgtype_column_size(const StatementClass *stmt, OID type, int col, int handle_unknown_size_as)
+{
+   int atttypmod, adtsize_or_longestlen;
 
-           /* Handle Character types and unknown types */
-           return getCharColumnSize(stmt, type, col, handle_unknown_size_as);
-   }
+   atttypmod = getAtttypmodEtc(stmt, col, &adtsize_or_longestlen);
+   return pgtype_attr_column_size(SC_get_conn(stmt), type, atttypmod, adtsize_or_longestlen, stmt->catalog_result ? UNKNOWNS_AS_CATALOG : handle_unknown_size_as); 
 }
 
 /*
  * precision in ODBC 3.x.
  */
 SQLSMALLINT
-pgtype_precision(StatementClass *stmt, OID type, int col, int handle_unknown_size_as)
+pgtype_precision(const StatementClass *stmt, OID type, int col, int handle_unknown_size_as)
 {
-   switch (type)
-   {
-       case PG_TYPE_NUMERIC:
-           return getNumericColumnSize(stmt, type, col);
-       case PG_TYPE_DATETIME:
-       case PG_TYPE_TIMESTAMP_NO_TMZONE:
-           return getTimestampDecimalDigits(stmt, type, col);
-   }
-   return -1;
+   int atttypmod, adtsize_or_longestlen;
+
+   atttypmod = getAtttypmodEtc(stmt, col, &adtsize_or_longestlen);
+   return pgtype_attr_precision(SC_get_conn(stmt), type, atttypmod, adtsize_or_longestlen, stmt->catalog_result ? UNKNOWNS_AS_CATALOG : handle_unknown_size_as); 
 }
 
 
 Int4
-pgtype_display_size(StatementClass *stmt, OID type, int col, int handle_unknown_size_as)
+pgtype_display_size(const StatementClass *stmt, OID type, int col, int handle_unknown_size_as)
 {
-   int dsize;
-
-   switch (type)
-   {
-       case PG_TYPE_INT2:
-           return 6;
+   int atttypmod, adtsize_or_longestlen;
 
-       case PG_TYPE_OID:
-       case PG_TYPE_XID:
-           return 10;
-
-       case PG_TYPE_INT4:
-           return 11;
-
-       case PG_TYPE_INT8:
-           return 20;          /* signed: 19 digits + sign */
-
-       case PG_TYPE_NUMERIC:
-           dsize = getNumericColumnSize(stmt, type, col);
-           return dsize < 0 ? dsize : dsize + 2;
-
-       case PG_TYPE_MONEY:
-           return 15;          /* ($9,999,999.99) */
-
-       case PG_TYPE_FLOAT4:
-           return 13;
-
-       case PG_TYPE_FLOAT8:
-           return 22;
-
-#if (ODBCVER >= 0x0350)
-       case PG_TYPE_UUID:
-           return 36;
-#endif /* ODBCVER */
-
-           /* Character types use regular precision */
-       default:
-           return pgtype_column_size(stmt, type, col, handle_unknown_size_as);
-   }
+   atttypmod = getAtttypmodEtc(stmt, col, &adtsize_or_longestlen);
+   return pgtype_attr_display_size(SC_get_conn(stmt), type, atttypmod, adtsize_or_longestlen, stmt->catalog_result ? UNKNOWNS_AS_CATALOG : handle_unknown_size_as); 
 }
 
 
@@ -1065,125 +1795,31 @@ pgtype_display_size(StatementClass *stmt, OID type, int col, int handle_unknown_
  * or SQLFetchScroll operation if SQL_C_DEFAULT is specified.
  */
 Int4
-pgtype_buffer_length(StatementClass *stmt, OID type, int col, int handle_unknown_size_as)
+pgtype_buffer_length(const StatementClass *stmt, OID type, int col, int handle_unknown_size_as)
 {
-   ConnectionClass *conn = SC_get_conn(stmt);
-
-   switch (type)
-   {
-       case PG_TYPE_INT2:
-           return 2; /* sizeof(SQLSMALLINT) */
-
-       case PG_TYPE_OID:
-       case PG_TYPE_XID:
-       case PG_TYPE_INT4:
-           return 4; /* sizeof(SQLINTEGER) */
-
-       case PG_TYPE_INT8:
-           if (SQL_C_CHAR == pgtype_to_ctype(stmt, type))
-               return 20;          /* signed: 19 digits + sign */
-           return 8; /* sizeof(SQLSBININT) */
-
-       case PG_TYPE_NUMERIC:
-           return getNumericColumnSize(stmt, type, col) + 2;
-
-       case PG_TYPE_FLOAT4:
-       case PG_TYPE_MONEY:
-           return 4; /* sizeof(SQLREAL) */
-
-       case PG_TYPE_FLOAT8:
-           return 8; /* sizeof(SQLFLOAT) */
-
-       case PG_TYPE_DATE:
-       case PG_TYPE_TIME:
-           return 6;       /* sizeof(DATE(TIME)_STRUCT) */
-
-       case PG_TYPE_ABSTIME:
-       case PG_TYPE_DATETIME:
-       case PG_TYPE_TIMESTAMP:
-       case PG_TYPE_TIMESTAMP_NO_TMZONE:
-           return 16;      /* sizeof(TIMESTAMP_STRUCT) */
+   int atttypmod, adtsize_or_longestlen;
 
-       case PG_TYPE_UUID:
-           return 16;      /* sizeof(SQLGUID) */
-
-           /* Character types use the default precision */
-       case PG_TYPE_VARCHAR:
-       case PG_TYPE_BPCHAR:
-           {
-           int coef = 1;
-           Int4    prec = pgtype_column_size(stmt, type, col, handle_unknown_size_as), maxvarc;
-           if (SQL_NO_TOTAL == prec)
-               return prec;
-#ifdef UNICODE_SUPPORT
-           if (CC_is_in_unicode_driver(conn))
-               return prec * WCLEN;
-#endif /* UNICODE_SUPPORT */
-           /* after 7.2 */
-           if (PG_VERSION_GE(conn, 7.2))
-               coef = conn->mb_maxbyte_per_char;
-           if (coef < 2 && (conn->connInfo).lf_conversion)
-               /* CR -> CR/LF */
-               coef = 2;
-           if (coef == 1)
-               return prec;
-           maxvarc = conn->connInfo.drivers.max_varchar_size;
-           if (prec <= maxvarc && prec * coef > maxvarc)
-               return maxvarc;
-           return coef * prec;
-           }
-       default:
-           return pgtype_column_size(stmt, type, col, handle_unknown_size_as);
-   }
+   atttypmod = getAtttypmodEtc(stmt, col, &adtsize_or_longestlen);
+   return pgtype_attr_buffer_length(SC_get_conn(stmt), type, atttypmod, adtsize_or_longestlen, stmt->catalog_result ? UNKNOWNS_AS_CATALOG : handle_unknown_size_as); 
 }
 
 /*
  */
 Int4
-pgtype_desclength(StatementClass *stmt, OID type, int col, int handle_unknown_size_as)
+pgtype_desclength(const StatementClass *stmt, OID type, int col, int handle_unknown_size_as)
 {
-   switch (type)
-   {
-       case PG_TYPE_INT2:
-           return 2;
-
-       case PG_TYPE_OID:
-       case PG_TYPE_XID:
-       case PG_TYPE_INT4:
-           return 4;
-
-       case PG_TYPE_INT8:
-           return 20;          /* signed: 19 digits + sign */
-
-       case PG_TYPE_NUMERIC:
-           return getNumericColumnSize(stmt, type, col) + 2;
-
-       case PG_TYPE_FLOAT4:
-       case PG_TYPE_MONEY:
-           return 4;
-
-       case PG_TYPE_FLOAT8:
-           return 8;
+   int atttypmod, adtsize_or_longestlen;
 
-       case PG_TYPE_DATE:
-       case PG_TYPE_TIME:
-       case PG_TYPE_ABSTIME:
-       case PG_TYPE_DATETIME:
-       case PG_TYPE_TIMESTAMP_NO_TMZONE:
-       case PG_TYPE_TIMESTAMP:
-       case PG_TYPE_VARCHAR:
-       case PG_TYPE_BPCHAR:
-           return pgtype_column_size(stmt, type, col, handle_unknown_size_as);
-       default:
-           return pgtype_column_size(stmt, type, col, handle_unknown_size_as);
-   }
+   atttypmod = getAtttypmodEtc(stmt, col, &adtsize_or_longestlen);
+   return pgtype_attr_desclength(SC_get_conn(stmt), type, atttypmod, adtsize_or_longestlen, stmt->catalog_result ? UNKNOWNS_AS_CATALOG : handle_unknown_size_as); 
 }
 
+#ifdef NOT_USED
 /*
  * Transfer octet length.
  */
 Int4
-pgtype_transfer_octet_length(StatementClass *stmt, OID type, int column_size)
+pgtype_transfer_octet_length(const StatementClass *stmt, OID type, int column_size)
 {
    ConnectionClass *conn = SC_get_conn(stmt);
 
@@ -1220,12 +1856,13 @@ pgtype_transfer_octet_length(StatementClass *stmt, OID type, int column_size)
    }
    return -1;
 }
+#endif /* NOT_USED */
 
 /*
  * corrsponds to "min_scale" in ODBC 2.x.
  */
 Int2
-pgtype_min_decimal_digits(StatementClass *stmt, OID type)
+pgtype_min_decimal_digits(const ConnectionClass *conn, OID type)
 {
    switch (type)
    {
@@ -1253,7 +1890,7 @@ pgtype_min_decimal_digits(StatementClass *stmt, OID type)
  * corrsponds to "max_scale" in ODBC 2.x.
  */
 Int2
-pgtype_max_decimal_digits(StatementClass *stmt, OID type)
+pgtype_max_decimal_digits(const ConnectionClass *conn, OID type)
 {
    switch (type)
    {
@@ -1273,7 +1910,7 @@ pgtype_max_decimal_digits(StatementClass *stmt, OID type)
        case PG_TYPE_TIMESTAMP_NO_TMZONE:
            return 38;
        case PG_TYPE_NUMERIC:
-           return getNumericDecimalDigits(stmt, type, -1);
+           return getNumericDecimalDigitsX(conn, type, -1, -1, UNKNOWNS_AS_DEFAULT); 
        default:
            return -1;
    }
@@ -1283,57 +1920,29 @@ pgtype_max_decimal_digits(StatementClass *stmt, OID type)
  * corrsponds to "scale" in ODBC 2.x.
  */
 Int2
-pgtype_decimal_digits(StatementClass *stmt, OID type, int col)
+pgtype_decimal_digits(const StatementClass *stmt, OID type, int col)
 {
-   switch (type)
-   {
-       case PG_TYPE_INT2:
-       case PG_TYPE_OID:
-       case PG_TYPE_XID:
-       case PG_TYPE_INT4:
-       case PG_TYPE_INT8:
-       case PG_TYPE_FLOAT4:
-       case PG_TYPE_FLOAT8:
-       case PG_TYPE_MONEY:
-       case PG_TYPE_BOOL:
-
-           /*
-            * Number of digits to the right of the decimal point in
-            * "yyyy-mm=dd hh:mm:ss[.f...]"
-            */
-       case PG_TYPE_ABSTIME:
-       case PG_TYPE_TIMESTAMP:
-           return 0;
-       case PG_TYPE_DATETIME:
-       case PG_TYPE_TIMESTAMP_NO_TMZONE:
-           /* return 0; */
-           return getTimestampDecimalDigits(stmt, type, col);
-
-       case PG_TYPE_NUMERIC:
-           return getNumericDecimalDigits(stmt, type, col);
+   int atttypmod, adtsize_or_longestlen;
 
-       default:
-           return -1;
-   }
+   atttypmod = getAtttypmodEtc(stmt, col, &adtsize_or_longestlen);
+   return pgtype_attr_decimal_digits(SC_get_conn(stmt), type, atttypmod, adtsize_or_longestlen, stmt->catalog_result ? UNKNOWNS_AS_CATALOG : UNKNOWNS_AS_DEFAULT); 
 }
 
 /*
  * "scale" in ODBC 3.x.
  */
 Int2
-pgtype_scale(StatementClass *stmt, OID type, int col)
+pgtype_scale(const StatementClass *stmt, OID type, int col)
 {
-   switch (type)
-   {
-       case PG_TYPE_NUMERIC:
-           return getNumericDecimalDigits(stmt, type, col);
-   }
-   return -1;
+   int atttypmod, adtsize_or_longestlen;
+
+   atttypmod = getAtttypmodEtc(stmt, col, &adtsize_or_longestlen);
+   return pgtype_attr_scale(SC_get_conn(stmt), type, atttypmod, adtsize_or_longestlen, stmt->catalog_result ? UNKNOWNS_AS_CATALOG : UNKNOWNS_AS_DEFAULT); 
 }
 
 
 Int2
-pgtype_radix(StatementClass *stmt, OID type)
+pgtype_radix(const ConnectionClass *conn, OID type)
 {
    switch (type)
    {
@@ -1354,14 +1963,14 @@ pgtype_radix(StatementClass *stmt, OID type)
 
 
 Int2
-pgtype_nullable(StatementClass *stmt, OID type)
+pgtype_nullable(const ConnectionClass *conn, OID type)
 {
    return SQL_NULLABLE;        /* everything should be nullable */
 }
 
 
 Int2
-pgtype_auto_increment(StatementClass *stmt, OID type)
+pgtype_auto_increment(const ConnectionClass *conn, OID type)
 {
    switch (type)
    {
@@ -1392,7 +2001,7 @@ pgtype_auto_increment(StatementClass *stmt, OID type)
 
 
 Int2
-pgtype_case_sensitive(StatementClass *stmt, OID type)
+pgtype_case_sensitive(const ConnectionClass *conn, OID type)
 {
    switch (type)
    {
@@ -1406,6 +2015,7 @@ pgtype_case_sensitive(StatementClass *stmt, OID type)
        case PG_TYPE_BPCHAR:
        case PG_TYPE_TEXT:
        case PG_TYPE_NAME:
+       case PG_TYPE_REFCURSOR:
            return TRUE;
 
        default:
@@ -1415,7 +2025,7 @@ pgtype_case_sensitive(StatementClass *stmt, OID type)
 
 
 Int2
-pgtype_money(StatementClass *stmt, OID type)
+pgtype_money(const ConnectionClass *conn, OID type)
 {
    switch (type)
    {
@@ -1428,7 +2038,7 @@ pgtype_money(StatementClass *stmt, OID type)
 
 
 Int2
-pgtype_searchable(StatementClass *stmt, OID type)
+pgtype_searchable(const ConnectionClass *conn, OID type)
 {
    switch (type)
    {
@@ -1441,10 +2051,11 @@ pgtype_searchable(StatementClass *stmt, OID type)
        case PG_TYPE_BPCHAR:
        case PG_TYPE_TEXT:
        case PG_TYPE_NAME:
+       case PG_TYPE_REFCURSOR:
            return SQL_SEARCHABLE;
 
        default:
-           if (stmt && type == SC_get_conn(stmt)->lobj_type)
+           if (conn && type == conn->lobj_type)
                return SQL_UNSEARCHABLE;
            return SQL_ALL_EXCEPT_LIKE;
    }
@@ -1452,7 +2063,7 @@ pgtype_searchable(StatementClass *stmt, OID type)
 
 
 Int2
-pgtype_unsigned(StatementClass *stmt, OID type)
+pgtype_unsigned(const ConnectionClass *conn, OID type)
 {
    switch (type)
    {
@@ -1476,7 +2087,7 @@ pgtype_unsigned(StatementClass *stmt, OID type)
 
 
 const char *
-pgtype_literal_prefix(StatementClass *stmt, OID type)
+pgtype_literal_prefix(const ConnectionClass *conn, OID type)
 {
    switch (type)
    {
@@ -1498,7 +2109,7 @@ pgtype_literal_prefix(StatementClass *stmt, OID type)
 
 
 const char *
-pgtype_literal_suffix(StatementClass *stmt, OID type)
+pgtype_literal_suffix(const ConnectionClass *conn, OID type)
 {
    switch (type)
    {
@@ -1520,7 +2131,7 @@ pgtype_literal_suffix(StatementClass *stmt, OID type)
 
 
 const char *
-pgtype_create_params(StatementClass *stmt, OID type)
+pgtype_create_params(const ConnectionClass *conn, OID type)
 {
    switch (type)
    {
@@ -1682,6 +2293,22 @@ ctype_length(SQLSMALLINT ctype)
        case SQL_C_GUID:
            return sizeof(SQLGUID);
 #endif /* ODBCVER */
+#if (ODBCVER >= 0x0300)
+       case SQL_C_INTERVAL_YEAR:
+       case SQL_C_INTERVAL_MONTH:
+       case SQL_C_INTERVAL_YEAR_TO_MONTH:
+       case SQL_C_INTERVAL_DAY:
+       case SQL_C_INTERVAL_HOUR:
+       case SQL_C_INTERVAL_DAY_TO_HOUR:
+       case SQL_C_INTERVAL_MINUTE:
+       case SQL_C_INTERVAL_DAY_TO_MINUTE:
+       case SQL_C_INTERVAL_HOUR_TO_MINUTE:
+       case SQL_C_INTERVAL_SECOND:
+       case SQL_C_INTERVAL_DAY_TO_SECOND:
+       case SQL_C_INTERVAL_HOUR_TO_SECOND:
+       case SQL_C_INTERVAL_MINUTE_TO_SECOND:
+           return sizeof(SQL_INTERVAL_STRUCT);
+#endif /* ODBCVER */
 
        case SQL_C_BINARY:
        case SQL_C_CHAR:
index f81ed20b170b2fcee3f9f0944620db02a4c76c34..dae2573abfb0d31a7cf41747c46a2fb668e4e854 100644 (file)
--- a/pgtypes.h
+++ b/pgtypes.h
@@ -69,6 +69,7 @@
 #define PG_TYPE_TIME           1083
 #define PG_TYPE_TIMESTAMP_NO_TMZONE    1114        /* since 7.2 */
 #define PG_TYPE_DATETIME       1184
+#define PG_TYPE_INTERVAL       1186
 #define PG_TYPE_TIME_WITH_TMZONE   1266        /* since 7.1 */
 #define PG_TYPE_TIMESTAMP      1296    /* deprecated since 7.0 */
 #define PG_TYPE_NUMERIC            1700
@@ -83,40 +84,61 @@ extern SQLSMALLINT sqlTypes[];
 
 /* Defines for pgtype_precision */
 #define PG_STATIC              (-1)
+#define PG_UNSPECIFIED             (-1)
 #define PG_WIDTH_OF_BOOLS_AS_CHAR      5
 
+#if (ODBCVER >= 0x0300)
+/* 
+ * SQL_INTERVAL support is disabled because I found
+ * some applications which are unhappy with it.
+ *
+#define    PG_INTERVAL_AS_SQL_INTERVAL
+ */
+#endif /* ODBCVER */
+
 OID        pg_true_type(const ConnectionClass *, OID, OID);
-OID        sqltype_to_pgtype(StatementClass *stmt, SQLSMALLINT fSqlType);
+OID        sqltype_to_pgtype(const ConnectionClass *conn, SQLSMALLINT fSqlType);
 
-SQLSMALLINT    pgtype_to_concise_type(StatementClass *stmt, OID type, int col);
-SQLSMALLINT    pgtype_to_sqldesctype(StatementClass *stmt, OID type, int col);
-SQLSMALLINT    pgtype_to_datetime_sub(StatementClass *stmt, OID type);
-SQLSMALLINT    pgtype_to_ctype(StatementClass *stmt, OID type);
-const char *pgtype_to_name(StatementClass *stmt, OID type, BOOL auto_increment);
+SQLSMALLINT    pgtype_to_concise_type(const StatementClass *stmt, OID type, int col);
+SQLSMALLINT    pgtype_to_sqldesctype(const StatementClass *stmt, OID type, int col);
+SQLSMALLINT    pgtype_to_datetime_sub(const StatementClass *stmt, OID type, int col);
+SQLSMALLINT    pgtype_to_ctype(const StatementClass *stmt, OID type, int col);
+const char *pgtype_to_name(const StatementClass *stmt, OID type, int col, BOOL auto_increment);
+
+SQLSMALLINT    pgtype_attr_to_concise_type(const ConnectionClass *conn, OID type, int typmod, int adtsize_or_longestlen);
+SQLSMALLINT    pgtype_attr_to_sqldesctype(const ConnectionClass *conn, OID type, int typmod);
+SQLSMALLINT    pgtype_attr_to_datetime_sub(const ConnectionClass *conn, OID type, int typmod);
+SQLSMALLINT    pgtype_attr_to_ctype(const ConnectionClass *conn, OID type, int typmod);
+const char *pgtype_attr_to_name(const ConnectionClass *conn, OID type, int typmod, BOOL auto_increment);
+Int4       pgtype_attr_column_size(const ConnectionClass *conn, OID type, int atttypmod, int adtsize_or_longest, int handle_unknown_size_as);
+Int4       pgtype_attr_buffer_length(const ConnectionClass *conn, OID type, int atttypmod, int adtsize_or_longestlen, int handle_unknown_size_as);
+Int4       pgtype_attr_display_size(const ConnectionClass *conn, OID type, int atttypmod, int adtsize_or_longestlen, int handle_unknown_size_as);
+Int2       pgtype_attr_decimal_digits(const ConnectionClass *conn, OID type, int atttypmod, int adtsize_or_longestlen, int handle_unknown_size_as);
+Int4       pgtype_attr_transfer_octet_length(const ConnectionClass *conn, OID type, int atttypmod, int handle_unknown_size_as);
 
 /* These functions can use static numbers or result sets(col parameter) */
-Int4       pgtype_column_size(StatementClass *stmt, OID type, int col, int handle_unknown_size_as); /* corresponds to "precision" in ODBC 2.x */
-SQLSMALLINT    pgtype_precision(StatementClass *stmt, OID type, int col, int handle_unknown_size_as); /* "precsion in ODBC 3.x */
+Int4       pgtype_column_size(const StatementClass *stmt, OID type, int col, int handle_unknown_size_as); /* corresponds to "precision" in ODBC 2.x */
+SQLSMALLINT    pgtype_precision(const StatementClass *stmt, OID type, int col, int handle_unknown_size_as); /* "precsion in ODBC 3.x */
 /* the following size/length are of Int4 due to PG restriction */ 
-Int4       pgtype_display_size(StatementClass *stmt, OID type, int col, int handle_unknown_size_as);
-Int4       pgtype_buffer_length(StatementClass *stmt, OID type, int col, int handle_unknown_size_as);
-Int4       pgtype_desclength(StatementClass *stmt, OID type, int col, int handle_unknown_size_as);
-Int4       pgtype_transfer_octet_length(StatementClass *stmt, OID type, int column_size);
-
-SQLSMALLINT    pgtype_decimal_digits(StatementClass *stmt, OID type, int col); /* corresponds to "scale" in ODBC 2.x */
-SQLSMALLINT    pgtype_min_decimal_digits(StatementClass *stmt, OID type); /* corresponds to "min_scale" in ODBC 2.x */
-SQLSMALLINT    pgtype_max_decimal_digits(StatementClass *stmt, OID type); /* corresponds to "max_scale" in ODBC 2.x */
-SQLSMALLINT    pgtype_scale(StatementClass *stmt, OID type, int col); /* ODBC 3.x " */
-Int2       pgtype_radix(StatementClass *stmt, OID type);
-Int2       pgtype_nullable(StatementClass *stmt, OID type);
-Int2       pgtype_auto_increment(StatementClass *stmt, OID type);
-Int2       pgtype_case_sensitive(StatementClass *stmt, OID type);
-Int2       pgtype_money(StatementClass *stmt, OID type);
-Int2       pgtype_searchable(StatementClass *stmt, OID type);
-Int2       pgtype_unsigned(StatementClass *stmt, OID type);
-const char *pgtype_literal_prefix(StatementClass *stmt, OID type);
-const char *pgtype_literal_suffix(StatementClass *stmt, OID type);
-const char *pgtype_create_params(StatementClass *stmt, OID type);
+Int4       pgtype_display_size(const StatementClass *stmt, OID type, int col, int handle_unknown_size_as);
+Int4       pgtype_buffer_length(const StatementClass *stmt, OID type, int col, int handle_unknown_size_as);
+Int4       pgtype_desclength(const StatementClass *stmt, OID type, int col, int handle_unknown_size_as);
+// Int4        pgtype_transfer_octet_length(const ConnectionClass *conn, OID type, int column_size);
+
+SQLSMALLINT    pgtype_decimal_digits(const StatementClass *stmt, OID type, int col); /* corresponds to "scale" in ODBC 2.x */
+SQLSMALLINT    pgtype_min_decimal_digits(const ConnectionClass *conn, OID type); /* corresponds to "min_scale" in ODBC 2.x */
+SQLSMALLINT    pgtype_max_decimal_digits(const ConnectionClass *conn, OID type); /* corresponds to "max_scale" in ODBC 2.x */
+SQLSMALLINT    pgtype_scale(const StatementClass *stmt, OID type, int col); /* ODBC 3.x " */
+Int2       pgtype_radix(const ConnectionClass *conn, OID type);
+Int2       pgtype_nullable(const ConnectionClass *conn, OID type);
+Int2       pgtype_auto_increment(const ConnectionClass *conn, OID type);
+Int2       pgtype_case_sensitive(const ConnectionClass *conn, OID type);
+Int2       pgtype_money(const ConnectionClass *conn, OID type);
+Int2       pgtype_searchable(const ConnectionClass *conn, OID type);
+Int2       pgtype_unsigned(const ConnectionClass *conn, OID type);
+const char *pgtype_literal_prefix(const ConnectionClass *conn, OID type);
+const char *pgtype_literal_suffix(const ConnectionClass *conn, OID type);
+const char *pgtype_create_params(const ConnectionClass *conn, OID type);
 
 SQLSMALLINT    sqltype_to_default_ctype(const ConnectionClass *stmt, SQLSMALLINT sqltype);
 Int4       ctype_length(SQLSMALLINT ctype);
index 01c24db92328c27a80697454f499bb98843b71e4..6aaf8d31a006129a04efe5c5f9c3100cfc0b2109 100644 (file)
--- a/qresult.c
+++ b/qresult.c
@@ -634,9 +634,13 @@ QR_close(QResultClass *self)
        }
        else
        {
-           UDWORD      flag = ROLLBACK_ON_ERROR | IGNORE_ABORT_ON_CONN;
+           BOOL        does_commit = FALSE;
+           UDWORD      flag = 0;
            char        buf[64];
 
+           if (QR_needs_survival_check(self))
+               flag = ROLLBACK_ON_ERROR | IGNORE_ABORT_ON_CONN;
+
            snprintf(buf, sizeof(buf), "close \"%s\"", QR_get_cursor(self));
            /* End the transaction if there are no cursors left on this conn */
            if (CC_is_in_trans(conn) &&
@@ -644,13 +648,27 @@ QR_close(QResultClass *self)
                CC_cursor_count(conn) <= 1)
            {
                mylog("QResult: END transaction on conn=%p\n", conn);
-               strlcat(buf, ";commit", sizeof(buf));
-               flag |= END_WITH_COMMIT;
-               QR_set_cursor(self, NULL);
+               if ((ROLLBACK_ON_ERROR & flag) == 0)
+               {
+                   strlcat(buf, ";commit", sizeof(buf));
+                   flag |= END_WITH_COMMIT;
+                   QR_set_cursor(self, NULL);
+               }
+               else
+                   does_commit = TRUE;
            }
 
            res = CC_send_query(conn, buf, NULL, flag, NULL);
            QR_Destructor(res);
+           if (does_commit)
+           {
+               if (!CC_commit(conn))
+               {
+                   QR_set_rstatus(self, PORES_FATAL_ERROR);
+                   QR_set_message(self, "Error ending transaction on autocommit.");
+                   ret = FALSE;
+               }
+           }
        }
 
        QR_set_no_fetching_tuples(self);
index 216db20d48c9685956f504596da547c17cb474c8..6af353cfebae1059c68ac90f34b576f4ced92674 100644 (file)
--- a/qresult.h
+++ b/qresult.h
@@ -46,6 +46,7 @@ enum
    FQR_FETCHING_TUPLES = 1L    /* is fetching tuples from db */
    ,FQR_REACHED_EOF = (1L << 1)    /* reached eof */
    ,FQR_HAS_VALID_BASE = (1L << 2)
+   ,FQR_NEEDS_SURVIVAL_CHECK = (1L << 3) /* check if the cursor is open */
 };
 
 struct QResultClass_
@@ -158,7 +159,7 @@ enum {
 #define QR_set_aborted(self, aborted_)     ( self->aborted = aborted_)
 #define QR_set_haskeyset(self)     (self->flags |= FQR_HASKEYSET)
 #define QR_set_synchronize_keys(self)  (self->flags |= FQR_SYNCHRONIZEKEYS)
-#define QR_set_no_cursor(self)     (self->flags &= ~(FQR_WITHHOLD | FQR_HOLDPERMANENT))
+#define QR_set_no_cursor(self)     (self->flags &= ~(FQR_WITHHOLD | FQR_HOLDPERMANENT | FQR_NEEDS_SURVIVAL_CHECK))
 #define QR_set_withhold(self)      (self->flags |= FQR_WITHHOLD)
 #define QR_set_permanent(self)     (self->flags |= FQR_HOLDPERMANENT)
 #define    QR_set_reached_eof(self)    (self->pstatus |= FQR_REACHED_EOF)
@@ -166,6 +167,8 @@ enum {
 #define    QR_set_no_fetching_tuples(self) (self->pstatus &= ~FQR_FETCHING_TUPLES)
 #define QR_set_has_valid_base(self)    (self->pstatus |= FQR_HAS_VALID_BASE)
 #define QR_set_no_valid_base(self) (self->pstatus &= ~FQR_HAS_VALID_BASE)
+#define QR_set_survival_check(self)    (self->pstatus |= FQR_NEEDS_SURVIVAL_CHECK)
+#define QR_set_no_survival_check(self) (self->pstatus &= ~FQR_NEEDS_SURVIVAL_CHECK)
 #define    QR_inc_num_cache(self) \
 do { \
    self->num_cached_rows++; \
@@ -195,6 +198,7 @@ do { \
 #define QR_once_reached_eof(self)  ((self->pstatus & FQR_REACHED_EOF) != 0)
 #define QR_is_fetching_tuples(self)    ((self->pstatus & FQR_FETCHING_TUPLES) != 0)
 #define    QR_has_valid_base(self)     (0 != (self->pstatus & FQR_HAS_VALID_BASE))
+#define    QR_needs_survival_check(self)       (0 != (self->pstatus & FQR_NEEDS_SURVIVAL_CHECK))
 
 #define QR_aborted(self)       (!self || self->aborted)
 #define QR_get_reqsize(self)       (self->rowset_size_include_ommitted)
index 2b725853b9dd962f7760d8485e5b164db08306b4..12a772b5d02f94cfaa53c0483174daaa2f1c0d7b 100644 (file)
--- a/results.c
+++ b/results.c
@@ -429,7 +429,7 @@ inolog("answering bookmark info\n");
        if (SC_has_outer_join(stmt))
            *pfNullable = TRUE;
        else
-           *pfNullable = fi ? fi->nullable : pgtype_nullable(stmt, fieldtype);
+           *pfNullable = fi ? fi->nullable : pgtype_nullable(conn, fieldtype);
 
        mylog("describeCol: col %d  *pfNullable = %d\n", icol, *pfNullable);
    }
@@ -521,7 +521,9 @@ inolog("answering bookmark info\n");
    unknown_sizes = ci->drivers.unknown_sizes;
 
    /* not appropriate for SQLColAttributes() */
-   if (unknown_sizes == UNKNOWNS_AS_DONTKNOW)
+   if (stmt->catalog_result)
+       unknown_sizes = UNKNOWNS_AS_CATALOG;
+   else if (unknown_sizes == UNKNOWNS_AS_DONTKNOW)
        unknown_sizes = UNKNOWNS_AS_MAX;
 
    if (!stmt->catalog_result && SC_is_parse_forced(stmt) && stmt->statement_type == STMT_TYPE_SELECT)
@@ -638,7 +640,7 @@ inolog("answering bookmark info\n");
            if (fi && fi->auto_increment)
                value = TRUE;
            else
-               value = pgtype_auto_increment(stmt, field_type);
+               value = pgtype_auto_increment(conn, field_type);
            if (value == -1)    /* non-numeric becomes FALSE (ODBC Doc) */
                value = FALSE;
            mylog("AUTO_INCREMENT=%d\n", value);
@@ -646,7 +648,7 @@ inolog("answering bookmark info\n");
            break;
 
        case SQL_COLUMN_CASE_SENSITIVE: /* == SQL_DESC_CASE_SENSITIVE */
-           value = pgtype_case_sensitive(stmt, field_type);
+           value = pgtype_case_sensitive(conn, field_type);
            break;
 
            /*
@@ -694,7 +696,7 @@ inolog(" (%s,%s)", PRINT_NAME(fi->column_alias), PRINT_NAME(fi->column_name));
            break;
 
        case SQL_COLUMN_MONEY: /* == SQL_DESC_FIXED_PREC_SCALE */
-           value = pgtype_money(stmt, field_type);
+           value = pgtype_money(conn, field_type);
 inolog("COLUMN_MONEY=%d\n", value);
            break;
 
@@ -706,7 +708,7 @@ inolog("COLUMN_MONEY=%d\n", value);
            if (SC_has_outer_join(stmt))
                value = TRUE;
            else
-               value = fi ? fi->nullable : pgtype_nullable(stmt, field_type);
+               value = fi ? fi->nullable : pgtype_nullable(conn, field_type);
 inolog("COLUMN_NULLABLE=%d\n", value);
            break;
 
@@ -735,7 +737,7 @@ inolog("COLUMN_SCALE=%d\n", value);
            break;
 
        case SQL_COLUMN_SEARCHABLE: /* == SQL_DESC_SEARCHABLE */
-           value = pgtype_searchable(stmt, field_type);
+           value = pgtype_searchable(conn, field_type);
            break;
 
        case SQL_COLUMN_TABLE_NAME: /* == SQL_DESC_TABLE_NAME */
@@ -750,11 +752,11 @@ inolog("COLUMN_SCALE=%d\n", value);
            break;
 
        case SQL_COLUMN_TYPE_NAME: /* == SQL_DESC_TYPE_NAME */
-           p = pgtype_to_name(stmt, field_type, fi && fi->auto_increment);
+           p = pgtype_to_name(stmt, field_type, col_idx, fi && fi->auto_increment);
            break;
 
        case SQL_COLUMN_UNSIGNED: /* == SQL_DESC_UNSINGED */
-           value = pgtype_unsigned(stmt, field_type);
+           value = pgtype_unsigned(conn, field_type);
            if (value == -1)    /* non-numeric becomes TRUE (ODBC Doc) */
                value = SQL_TRUE;
 
@@ -798,14 +800,15 @@ inolog("COLUMN_SCALE=%d\n", value);
            mylog("%s: BASE_TABLE_NAME = '%s'\n", func, p);
            break;
        case SQL_DESC_LENGTH: /* different from SQL_COLUMN_LENGTH */
-           value = (fi && fi->length > 0) ? fi->length : pgtype_desclength(stmt, field_type, col_idx, unknown_sizes);
+           // value = (fi && fi->length > 0) ? fi->length : pgtype_desclength(stmt, field_type, col_idx, unknown_sizes);
+           value = (fi && column_size > 0) ? column_size : pgtype_desclength(stmt, field_type, col_idx, unknown_sizes);
            if (-1 == value)
                value = 0;
 
            mylog("%s: col %d, desc_length = %d\n", func, col_idx, value);
            break;
        case SQL_DESC_OCTET_LENGTH:
-           value = (fi && fi->length > 0) ? fi->length : pgtype_transfer_octet_length(stmt, field_type, column_size);
+           value = (fi && fi->length > 0) ? fi->length : pgtype_attr_transfer_octet_length(conn, field_type, column_size, unknown_sizes);
            if (-1 == value)
                value = 0;
            mylog("%s: col %d, octet_length = %d\n", func, col_idx, value);
@@ -824,19 +827,19 @@ inolog("COLUMN_SCALE=%d\n", value);
                value = 0;
            break;
        case SQL_DESC_LOCAL_TYPE_NAME:
-           p = pgtype_to_name(stmt, field_type, fi && fi->auto_increment);
+           p = pgtype_to_name(stmt, field_type, col_idx, fi && fi->auto_increment);
            break;
        case SQL_DESC_TYPE:
            value = pgtype_to_sqldesctype(stmt, field_type, col_idx);
            break;
        case SQL_DESC_NUM_PREC_RADIX:
-           value = pgtype_radix(stmt, field_type);
+           value = pgtype_radix(conn, field_type);
            break;
        case SQL_DESC_LITERAL_PREFIX:
-           p = pgtype_literal_prefix(stmt, field_type);
+           p = pgtype_literal_prefix(conn, field_type);
            break;
        case SQL_DESC_LITERAL_SUFFIX:
-           p = pgtype_literal_suffix(stmt, field_type);
+           p = pgtype_literal_suffix(conn, field_type);
            break;
        case SQL_DESC_UNNAMED:
            value = (fi && NAME_IS_NULL(fi->column_name) && NAME_IS_NULL(fi->column_alias)) ? SQL_UNNAMED : SQL_NAMED;
@@ -910,11 +913,13 @@ PGAPI_GetData(
    UInt2       num_cols;
    SQLLEN      num_rows;
    OID     field_type;
+   int     atttypmod;
    void       *value = NULL;
    RETCODE     result = SQL_SUCCESS;
    char        get_bookmark = FALSE;
    ConnInfo   *ci;
    SQLSMALLINT target_type;
+   int     precision = -1;
 
    mylog("%s: enter, stmt=%p icol=%d\n", func, stmt, icol);
 
@@ -952,6 +957,7 @@ PGAPI_GetData(
        {   
            target_type = binfo->returntype;
            mylog("SQL_ARD_TYPE=%d\n", target_type);
+           precision = binfo->precision;
        }
        else
        {
@@ -1067,13 +1073,14 @@ inolog("currT=%d base=%d rowset=%d\n", stmt->currTuple, QR_get_rowstart_in_cache
    }
 
    field_type = QR_get_field_type(res, icol);
+   atttypmod = QR_get_atttypmod(res, icol);
 
    mylog("**** %s: icol = %d, target_type = %d, field_type = %d, value = '%s'\n", func, icol, target_type, field_type, value ? value : "(null)");
 
    SC_set_current_col(stmt, icol);
 
-   result = copy_and_convert_field(stmt, field_type, value,
-               target_type, rgbValue, cbValueMax, pcbValue, pcbValue);
+   result = copy_and_convert_field(stmt, field_type, atttypmod, value,
+           target_type, precision, rgbValue, cbValueMax, pcbValue, pcbValue);
 
    switch (result)
    {
@@ -3941,8 +3948,10 @@ irow_insert(RETCODE ret, StatementClass *stmt, StatementClass *istmt, SQLLEN add
                SC_set_current_col(stmt, -1);
                copy_and_convert_field(stmt,
                    PG_TYPE_INT4,
+                   PG_UNSPECIFIED,
                    buf,
                                bookmark->returntype,
+                   0,
                    bookmark->buffer + offset,
                    bookmark->buflen,
                    LENADDR_SHIFT(bookmark->used, offset),
index 784c2e019f0145c4a1ddbadb07a3596903a72262..327b9078eedd139ee7d8ca2fe1c7ebe47ff22d78 100644 (file)
@@ -1532,13 +1532,14 @@ SC_fetch(StatementClass *self)
    Int2        num_cols,
                lf;
    OID         type;
+   int     atttypmod;
    char       *value;
    ColumnInfoClass *coli;
    BindInfoClass   *bookmark;
 
    /* TupleField *tupleField; */
 
-inolog("%s statement=%p ommitted=0\n", func, self);
+inolog("%s statement=%p res=%x ommitted=0\n", func, self, res);
    self->last_fetch_count = self->last_fetch_count_include_ommitted = 0;
    if (!res)
        return SQL_ERROR;
@@ -1641,8 +1642,8 @@ inolog("%s: stmt=%p ommitted++\n", func, self);
 
        sprintf(buf, FORMAT_ULEN, SC_get_bookmark(self));
        SC_set_current_col(self, -1);
-       result = copy_and_convert_field(self, 0, buf,
-            SQL_C_ULONG, bookmark->buffer + offset, 0,
+       result = copy_and_convert_field(self, 0, PG_UNSPECIFIED, buf,
+            SQL_C_ULONG, 0, bookmark->buffer + offset, 0,
            LENADDR_SHIFT(bookmark->used, offset),
            LENADDR_SHIFT(bookmark->used, offset));
    }
@@ -1670,8 +1671,9 @@ inolog("%s: stmt=%p ommitted++\n", func, self);
 
            /* type = QR_get_field_type(res, lf); */
            type = CI_get_oid(coli, lf);        /* speed things up */
+           atttypmod = CI_get_atttypmod(coli, lf); /* speed things up */
 
-           mylog("type = %d\n", type);
+           mylog("type = %d, atttypmod = %d\n", type, atttypmod);
 
            if (SC_is_fetchcursor(self))
                value = QR_get_value_backend(res, lf);
@@ -1685,7 +1687,7 @@ inolog("curt=%d\n", curt);
 
            mylog("value = '%s'\n", (value == NULL) ? "<NULL>" : value);
 
-           retval = copy_and_convert_field_bindinfo(self, type, value, lf);
+           retval = copy_and_convert_field_bindinfo(self, type, atttypmod, value, lf);
 
            mylog("copy_and_convert: retval = %d\n", retval);
 
@@ -2099,6 +2101,34 @@ inolog("res->next=%p\n", tres);
    {
        Int2    io, out;
        has_out_para = (CountParameters(self, NULL, &io, &out) > 0);
+/*
+ * I'm not sure if the following REFCIR_SUPPORT stuff is valuable
+ * or not.
+ */
+#ifdef REFCUR_SUPPORT
+
+inolog("!!! numfield=%d field_type=%u\n", QR_NumResultCols(res), QR_get_field_type(res, 0));
+       if (!has_out_para &&
+           0 < QR_NumResultCols(res) &&
+           PG_TYPE_REFCURSOR == QR_get_field_type(res, 0))
+       {
+           char    fetch[128];
+           int stmt_type = self->statement_type;
+
+           STR_TO_NAME(self->cursor_name, QR_get_value_backend_text(res, 0, 0));
+           QR_Destructor(res);
+           SC_init_Result(self);
+           SC_set_fetchcursor(self); 
+           qi.result_in = NULL;
+           qi.cursor = SC_cursor_name(self);
+           qi.row_size = ci->drivers.fetch_max;
+           snprintf(fetch, sizeof(fetch), "%s " FORMAT_LEN " in \"%s\"", fetch_cmd, qi.row_size, SC_cursor_name(self));
+           if (0 != (ci->extra_opts & BIT_IGNORE_ROUND_TRIP_TIME))
+               qflag |= IGNORE_ROUND_TRIP;
+           if (res = CC_send_query_append(conn, fetch, &qi, qflag, SC_get_ancestor(self), NULL), NULL != res)
+               SC_set_Result(self, res);
+       }
+#endif /* REFCUR_SUPPORT */
    }
    if (has_out_para)
    {   /* get the return value of the procedure call */
index af8cfe7b71993d41eac123cab176b593c21cce7c..bdfec4c97967a1e3f95eaf7eeee357df35154a62 100644 (file)
--- a/version.h
+++ b/version.h
@@ -9,9 +9,9 @@
 #ifndef __VERSION_H__
 #define __VERSION_H__
 
-#define POSTGRESDRIVERVERSION      "08.04.0201"
-#define POSTGRES_RESOURCE_VERSION  "08.04.0201\0"
-#define PG_DRVFILE_VERSION     8,4,02,01
-#define PG_BUILD_VERSION       "2010008210001"
+#define POSTGRESDRIVERVERSION      "08.04.0202"
+#define POSTGRES_RESOURCE_VERSION  "08.04.0202\0"
+#define PG_DRVFILE_VERSION     8,4,02,02
+#define PG_BUILD_VERSION       "201008210001"
 
 #endif