The version is now 8.2.0006.
authorHiroshi Inoue <inoue@tpf.co.jp>
Tue, 18 Jul 2006 21:20:46 +0000 (21:20 +0000)
committerHiroshi Inoue <inoue@tpf.co.jp>
Tue, 18 Jul 2006 21:20:46 +0000 (21:20 +0000)
 . Add an option to fake Microsoft SQL Server which would improve
   SERIAL type handling.
 . Add support for LOGIN_TIMEOUT.
 . Improve Statement error handling about the reference of Connection error.
 . Improve the handling BIGINT type in the OSs without having strtoll().
 . Support ODBC CONVERT scalar functions in some cases.
 . Close qlog, mylog files on detach dll.
 . Improve comunication performance in case of the driver's original
   socket.
 . Send a Close message at the end of normal command processing.

30 files changed:
bind.c
connection.c
connection.h
convert.c
descriptor.h
dlg_specific.c
dlg_specific.h
dlg_wingui.c
drvconn.c
execute.c
info.c
inouealc.c
misc.h
msdtc_enlist.cpp
mylog.c
odbcapiw.c
options.c
parse.c
pgapifunc.h
pgtypes.c
pgtypes.h
psqlodbc.c
psqlodbc.h
resource.h
results.c
socket.c
socket.h
statement.c
statement.h
version.h

diff --git a/bind.c b/bind.c
index f9866df8f0fc3409d3bda93adb107ebb0aadd651..3388a54c6d442f51f3260e41d1dbedf9de9ded2a 100644 (file)
--- a/bind.c
+++ b/bind.c
@@ -177,7 +177,6 @@ PGAPI_BindCol(
 
 #define    return  DONT_CALL_RETURN_FROM_HERE ???
    SC_clear_error(stmt);
-   /* StartRollbackState(stmt); */
    /* If the bookmark column is being bound, then just save it */
    if (icol == 0)
    {
index 8118d8baa5ca824c4a1fd2ce0a034b4d6481d2e1..1df0455a3bdc28ff1d7c23ff2e8422c746548215 100644 (file)
@@ -244,6 +244,9 @@ CC_conninfo_init(ConnInfo *conninfo)
        conninfo->use_server_side_prepare = -1;
        conninfo->lower_case_identifier = -1;
        conninfo->rollback_on_error = -1;
+       conninfo->force_abbrev_connstr = -1;
+       conninfo->fake_mss = -1;
+       conninfo->bde_environment = -1;
 #ifdef _HANDLE_ENLIST_IN_DTC_
        conninfo->xa_opt = -1;
        conninfo->autocommit_normal = 0;
@@ -369,6 +372,8 @@ CC_Destructor(ConnectionClass *self)
 #endif /* ODBCVER */
    mylog("after free statement holders\n");
 
+   NULL_THE_NAME(self->schemaIns);
+   NULL_THE_NAME(self->tableIns);
    if (self->__error_message)
        free(self->__error_message);
    DELETE_CONN_CS(self);
@@ -1034,6 +1039,7 @@ static int    protocol3_packet_build(ConnectionClass *self)
    return 1;
 }
 
+CSTR   l_login_timeout = "connect_timeout";
 static char    *protocol3_opts_build(ConnectionClass *self)
 {
    CSTR    func = "protocol3_opts_build";
@@ -1052,6 +1058,14 @@ static char  *protocol3_opts_build(ConnectionClass *self)
        slen += (strlen(opts[i][0]) + 2 + 2); /* add 2 bytes for safety (literal quotes) */
        slen += strlen(opts[i][1]);
    }
+   if (self->login_timeout > 0)
+   {
+       char    tmout[16];
+
+       slen += (strlen(l_login_timeout) + 2 + 2);
+       snprintf(tmout, sizeof(tmout), "%d", self->login_timeout);
+       slen += strlen(tmout);
+   }
    slen++;
                
    if (conninfo = malloc(slen), !conninfo)
@@ -1082,6 +1096,13 @@ static char  *protocol3_opts_build(ConnectionClass *self)
            ppacket++;
        }
    }
+   if (self->login_timeout > 0)
+   {
+       sprintf(ppacket, " %s=", l_login_timeout);
+       ppacket += (strlen(l_login_timeout) + 2);
+       sprintf(ppacket, "%d", self->login_timeout);
+       ppacket = strchr(ppacket, '\0');
+   }
    *ppacket = '\0';
 inolog("return conninfo=%s(%d)\n", conninfo, strlen(conninfo));
    return conninfo;
@@ -1217,7 +1238,7 @@ another_version_retry:
 
        mylog("connecting to the server socket...\n");
 
-       SOCK_connect_to(sock, (short) atoi(ci->port), ci->server);
+       SOCK_connect_to(sock, (short) atoi(ci->port), ci->server, self->login_timeout);
        if (SOCK_get_errcode(sock) != 0)
        {
            CC_set_error(self, CONNECTION_SERVER_NOT_REACHED, "Could not connect to the server", func);
@@ -1644,6 +1665,20 @@ CC_add_statement(ConnectionClass *self, StatementClass *stmt)
    return TRUE;
 }
 
+static void
+CC_set_error_statements(ConnectionClass *self)
+{
+   int i;
+
+   mylog("CC_error_statements: self=%x\n", self);
+
+   for (i = 0; i < self->num_stmts; i++)
+   {
+       if (NULL != self->stmts[i])
+           SC_ref_CC_error(self->stmts[i]);
+   }
+}
+
 
 char
 CC_remove_statement(ConnectionClass *self, StatementClass *stmt)
@@ -1717,6 +1752,8 @@ CC_set_error(ConnectionClass *self, int number, const char *message, const char
        free(self->__error_message);
    self->__error_number = number;
    self->__error_message = message ? strdup(message) : NULL;
+   if (0 != number)
+       CC_set_error_statements(self);
    if (func && number != 0)
        CC_log_error(func, "", self); 
 }
@@ -2969,6 +3006,7 @@ CC_send_cancel_request(const ConnectionClass *conn)
    }           crp;
    BOOL    ret = TRUE;
    SocketClass *sock;
+   struct sockaddr *sadr;
 
    /* Check we have an open connection */
    if (!conn)
@@ -2983,11 +3021,12 @@ CC_send_cancel_request(const ConnectionClass *conn)
     * We need to open a temporary connection to the postmaster. Use the
     * information saved by connectDB to do this with only kernel calls.
    */
-   if ((tmpsock = socket(conn->sock->sadr->sa_family, SOCK_STREAM, 0)) < 0)
+   sadr = (struct sockaddr *) &(sock->sadr_area);
+   if ((tmpsock = socket(sadr->sa_family, SOCK_STREAM, 0)) < 0)
    {
        return FALSE;
    }
-   if (connect(tmpsock, conn->sock->sadr, conn->sock->sadr_len) < 0)
+   if (connect(tmpsock, sadr, sock->sadr_len) < 0)
    {
        closesocket(tmpsock);
        return FALSE;
index 2810d4620c72211200dc903c61f3e863ffd2fd51..4243402678cdce1813ed98dc20db3c3d15b213c1 100644 (file)
@@ -291,6 +291,7 @@ typedef struct
    signed char rollback_on_error;
    signed char force_abbrev_connstr;
    signed char bde_environment;
+   signed char fake_mss;
 #ifdef _HANDLE_ENLIST_IN_DTC_
    signed char xa_opt;
    signed char autocommit_normal;
@@ -379,6 +380,7 @@ struct ConnectionClass_
 {
    HENV        henv;       /* environment this connection was
                     * created on */
+   SQLINTEGER  login_timeout;
    StatementOptions stmtOptions;
    ARDFields   ardOptions;
    APDFields   apdOptions;
@@ -432,6 +434,8 @@ struct ConnectionClass_
    int     num_descs;
    DescriptorClass **descs;
 #endif /* ODBCVER */
+   pgNAME      schemaIns;
+   pgNAME      tableIns;
 #if defined(WIN_MULTITHREAD_SUPPORT)
    CRITICAL_SECTION    cs;
 #elif defined(POSIX_THREADMUTEX_SUPPORT)
@@ -451,6 +455,7 @@ struct ConnectionClass_
 #define CC_get_username(x)         (x->connInfo.username)
 #define CC_is_onlyread(x)          (x->connInfo.onlyread[0] == '1')
 #define CC_get_escape(x)           (x->escape_in_literal)
+#define CC_fake_mss(x)     (0 != (x)->ms_jet && 0 < (x)->connInfo.fake_mss)
  
 /* for CC_DSN_info */
 #define CONN_DONT_OVERWRITE        0
index 7bb1f0a1c9ba768bc4534dec631942c22c98ea0f..0ed5c7788ca2a67670fd6f4e508c74ecbd5c0464 100644 (file)
--- a/convert.c
+++ b/convert.c
@@ -37,6 +37,7 @@
 #include "pgtypes.h"
 #include "lobj.h"
 #include "connection.h"
+#include "catfunc.h"
 #include "pgapifunc.h"
 
 #if defined(UNICODE_SUPPORT) && defined(WIN32)
@@ -179,13 +180,26 @@ static int pg_bin2hex(UCHAR *src, UCHAR *dst, int length);
 #define    ATOI64U(val)    strtoul(val, NULL, 10)
 #define    FORMATI64   "%ld"
 #define    FORMATI64U  "%lu"
-#elif  defined(HAVE_STRTOLL)
-#define    ATOI64(val) strtoll(val, NULL, 10)
-#define    ATOI64U(val)    strtoull(val, NULL, 10)
+#else
 #define    FORMATI64   "%lld"
 #define    FORMATI64U  "%llu"
-#else /* HAVE_STRTOLL */
-#error cant handle ODBCINT64
+#if    defined(HAVE_STRTOLL)
+#define    ATOI64(val) strtoll(val, NULL, 10)
+#define    ATOI64U(val)    strtoull(val, NULL, 10)
+#else
+static ODBCINT64 ATOI64(const char *val)
+{
+   ODBCINT64 ll;
+   sscanf(val, "%lld", &ll);
+   return ll;
+}
+static unsigned ODBCINT64 ATOI64U(const char *val)
+{
+   unsigned ODBCINT64 ll;
+   sscanf(val, "%llu", &ll);
+   return ll;
+}
+#endif /* HAVE_STRTOLL */
 #endif /* WIN32 */
 #endif /* ODBCINT64 */
 
@@ -2012,7 +2026,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, ipdopts->parameters[i].PGType));
+                   CVT_APPEND_STR(qb, pgtype_to_name(stmt, ipdopts->parameters[i].PGType, FALSE));
                oc++;
            }
            CVT_APPEND_CHAR(qb, ')');
@@ -2444,7 +2458,6 @@ inner_process_tokens(QueryParse *qp, QueryBuild *qb)
    /*
     * From here we are guaranteed to handle a 1-byte character.
     */
-
    if (qp->in_escape)          /* escape check */
    {
        qp->in_escape = FALSE;
@@ -2529,6 +2542,45 @@ inner_process_tokens(QueryParse *qp, QueryBuild *qb)
            CVT_APPEND_CHAR(qb, ' ');
        return SQL_SUCCESS;
    }
+   else if (oldchar == '@' &&
+        strnicmp(F_OldPtr(qp), "@@identity", 10) == 0)
+   {
+       ConnectionClass *conn = SC_get_conn(stmt);
+       BOOL        converted = FALSE;
+       COL_INFO    *coli;
+
+       if (NAME_IS_VALID(conn->tableIns))
+       {
+           TABLE_INFO  ti, *pti = &ti;
+
+           memset(&ti, 0, sizeof(ti));
+           NAME_TO_NAME(ti.schema_name, conn->schemaIns);
+           NAME_TO_NAME(ti.table_name, conn->tableIns);
+           getCOLIfromTI(func, conn, NULL, 0, &pti);
+           coli = ti.col_info;
+           NULL_THE_NAME(ti.schema_name);
+           NULL_THE_NAME(ti.table_name);
+           if (NULL != coli)
+           {
+               int i, num_fields = QR_NumResultCols(coli->result);
+
+               for (i = 0; i < num_fields; i++)
+               {
+                       if (*((char *)QR_get_value_backend_row(coli->result, i, COLUMNS_AUTO_INCREMENT)) == '1')
+                   {
+                       CVT_APPEND_STR(qb, "curr");
+                       CVT_APPEND_STR(qb, (char *)QR_get_value_backend_row(coli->result, i, COLUMNS_COLUMN_DEF) + 4);
+                       converted = TRUE;
+                       break;
+                   }
+               }
+           }
+       }
+       if (!converted)
+           CVT_APPEND_STR(qb, "0");
+       qp->opos += 10;
+       return SQL_SUCCESS;
+   }
 
    /*
     * Can you have parameter markers inside of quotes?  I dont think
@@ -3850,16 +3902,17 @@ convert_escape(QueryParse *qp, QueryBuild *qb)
    {
        QueryBuild  nqb;
        const char *mapExpr;
-       int i, param_count;
+       int i, param_count, from, to;
        UInt4   param_consumed;
        Int4    param_pos[16][2];
+       BOOL    cvt_func = FALSE;
 
        /* Separate off the func name, skipping leading and trailing whitespace */
        i = 0;
        while ((ucv = F_OldChar(qp)) != '\0' && ucv != '(' &&
               (!isspace(ucv)))
        {
-           if (i < sizeof(key)-1)
+           if (i < sizeof(key) - 1)
                key[i++] = ucv;
            F_OldNext(qp);
        }
@@ -3901,8 +3954,75 @@ convert_escape(QueryParse *qp, QueryBuild *qb)
            param_pos[0][1] < param_pos[0][0])
            param_count = 0;
 
-       mapExpr = mapFunction(key, param_count);
-       if (mapExpr == NULL)
+       mapExpr = NULL;
+       if (stricmp(key, "convert") == 0)
+           cvt_func = TRUE;
+       else
+           mapExpr = mapFunction(key, param_count);
+       if (cvt_func)
+       {
+           if (2 == param_count)
+           {
+               BOOL add_cast = FALSE, add_quote = FALSE;
+               const char *pptr;
+
+               from = param_pos[0][0];
+               to = param_pos[0][1];
+               for (pptr = nqb.query_statement + from; *pptr && isspace(*pptr); pptr++)
+                   ;
+               if (LITERAL_QUOTE == *pptr)
+                   ;
+               else if ('-' == *pptr)
+                   add_quote = TRUE;
+               else if (isdigit(*pptr))
+                   add_quote = TRUE;
+               else 
+                   add_cast = TRUE;
+               if (add_quote)
+                   CVT_APPEND_CHAR(qb, LITERAL_QUOTE);
+               else if (add_cast)
+                   CVT_APPEND_CHAR(qb, '(');
+               CVT_APPEND_DATA(qb, nqb.query_statement + from, to - from + 1);
+               if (add_quote)
+                   CVT_APPEND_CHAR(qb, LITERAL_QUOTE);
+               else if (add_cast)
+               {
+                   const char *cast_form = NULL;
+
+                   CVT_APPEND_CHAR(qb, ')');
+                   from = param_pos[1][0];
+                   to = param_pos[1][1];
+                   if (to < from + 9)
+                   {
+                       char    num[10];
+                       memcpy(num, nqb.query_statement + from, to - from + 1);
+                       num[to - from + 1] = '\0';
+mylog("%d-%d num=%s SQL_BIT=%d\n", to, from, num, SQL_BIT);
+                       switch (atoi(num))
+                       {
+                           case SQL_BIT:
+                               cast_form = "boolean";
+                               break;
+                           case SQL_INTEGER:
+                               cast_form = "int4";
+                               break;
+                       }
+                   }
+                   if (NULL != cast_form)
+                   {
+                       CVT_APPEND_STR(qb, "::");
+                       CVT_APPEND_STR(qb, cast_form);
+                   }
+               }
+           }
+           else
+           {
+               qb->errornumber = STMT_EXEC_ERROR;
+               qb->errormsg = "convert param count must be 2";
+               retval = SQL_ERROR;
+           }
+       }
+       else if (mapExpr == NULL)
        {
            CVT_APPEND_STR(qb, key);
            CVT_APPEND_DATA(qb, nqb.query_statement, nqb.npos);
@@ -3910,7 +4030,7 @@ convert_escape(QueryParse *qp, QueryBuild *qb)
        else
        {
            const char *mapptr;
-           int from, to, pidx, paramlen;
+           int pidx, paramlen;
 
            for (prtlen = 0, mapptr = mapExpr; *mapptr; mapptr++)
            {
@@ -3950,7 +4070,7 @@ convert_escape(QueryParse *qp, QueryBuild *qb)
                }
                paramlen = to - from + 1;
                if (paramlen > 0)
-                   CVT_APPEND_DATA(qb, nqb.query_statement+ from, paramlen);
+                   CVT_APPEND_DATA(qb, nqb.query_statement + from, paramlen);
            }
        }
        if (0 == qb->errornumber)
index fcd446c6d932f91a8f38aa931fa0fe0546ee2eab..8ee77424b92d7d59b7b2f96f5cc3d84448034504 100644 (file)
@@ -5,7 +5,7 @@
  *
  * Comments:       See "notice.txt" for copyright and license information.
  *
- * $Id: descriptor.h,v 1.15 2006/06/12 15:21:45 hinoue Exp $
+ * $Id: descriptor.h,v 1.16 2006/07/18 21:20:45 hinoue Exp $
  *
  */
 
@@ -18,16 +18,16 @@ typedef struct
 {
    char    *name;
 } pgNAME;
-#define    GET_NAME(the_name)  (the_name.name)
-#define    SAFE_NAME(the_name) (the_name.name ? the_name.name : NULL_STRING)
-#define    PRINT_NAME(the_name)    (the_name.name ? the_name.name : PRINT_NULL)
-#define    NAME_IS_NULL(the_name)  (NULL == the_name.name)
-#define    NAME_IS_VALID(the_name) (NULL != the_name.name)
-#define    INIT_NAME(the_name) (the_name.name = NULL)
+#define    GET_NAME(the_name)  ((the_name).name)
+#define    SAFE_NAME(the_name) ((the_name).name ? (the_name).name : NULL_STRING)
+#define    PRINT_NAME(the_name)    ((the_name).name ? (the_name).name : PRINT_NULL)
+#define    NAME_IS_NULL(the_name)  (NULL == (the_name).name)
+#define    NAME_IS_VALID(the_name) (NULL != (the_name).name)
+#define    INIT_NAME(the_name) ((the_name).name = NULL)
 #define    NULL_THE_NAME(the_name) \
 do { \
-   if (the_name.name) free(the_name.name); \
-   the_name.name = NULL; \
+   if ((the_name).name) free((the_name).name); \
+   (the_name).name = NULL; \
 } while (0)
 #define    STR_TO_NAME(the_name, str) \
 do { \
@@ -35,9 +35,22 @@ do { \
        free((the_name).name); \
    (the_name).name = (str ? strdup((str)) : NULL); \
 } while (0)
+#define    STRN_TO_NAME(the_name, str, n) \
+do { \
+   if ((the_name).name) \
+       free((the_name).name); \
+   if (str) \
+   { \
+       (the_name).name = malloc(n + 1); \
+       memcpy((the_name).name, str, n); \
+       (the_name).name[n] = '\0'; \
+   } \
+   else \
+       (the_name).name = NULL; \
+} while (0)
 #define    NAME_TO_STR(str, the_name) \
 do {\
-   if (the_name.name) strcpy(str, the_name.name); \
+   if ((the_name).name) strcpy(str, (the_name).name); \
    else *str = '\0'; \
 } while (0)
 #define    NAME_TO_NAME(to, from) \
@@ -235,7 +248,7 @@ BindInfoClass   *ARD_AllocBookmark(ARDFields *self);
 void   ARD_unbind_cols(ARDFields *self, BOOL freeall);
 void   APD_free_params(APDFields *self, char option);
 void   IPD_free_params(IPDFields *self, char option);
-BOOL   getCOLIfromTI(const char *, StatementClass *, const Oid, TABLE_INFO **);
+BOOL   getCOLIfromTI(const char *, ConnectionClass *, StatementClass *, const Oid, TABLE_INFO **);
 #if (ODBCVER >= 0x0300)
 RETCODE    DC_set_stmt(DescriptorClass *desc, StatementClass *stmt);
 void   DC_clear_error(DescriptorClass *desc);
index 16c0efbd61cf4e15bc4f1b5e3225747dd2f200b1..5d2a56fcd303c77f50f15eb43cf705e1eb64256f 100644 (file)
@@ -29,6 +29,84 @@ extern GLOBAL_VALUES globals;
 static void encode(const char *in, char *out);
 static void decode(const char *in, char *out);
 
+UInt4  getExtraOptions(const ConnInfo *ci)
+{
+   UInt4   flag = 0;
+
+   if (ci->force_abbrev_connstr)
+       flag |= BIT_FORCEABBREVCONNSTR;
+   if (ci->fake_mss)
+       flag |= BIT_FAKE_MSS;
+   if (ci->bde_environment)
+       flag |= BIT_BDE_ENVIRONMENT;
+       
+   return flag;
+}
+
+CSTR   hex_format = "%x";
+CSTR   dec_format = "%u";
+CSTR   octal_format = "%o";
+static UInt4   replaceExtraOptions(ConnInfo *ci, UInt4 flag, BOOL overwrite)
+{
+   if (overwrite || ci->force_abbrev_connstr < 0)
+       ci->force_abbrev_connstr = (0 != (flag & BIT_FORCEABBREVCONNSTR));
+   if (overwrite || ci->fake_mss < 0)
+       ci->fake_mss = (0 != (flag & BIT_FAKE_MSS));
+   if (overwrite || ci->bde_environment)
+       ci->bde_environment = (0 != (flag & BIT_BDE_ENVIRONMENT));
+       
+   return getExtraOptions(ci);
+}
+BOOL   setExtraOptions(ConnInfo *ci, const char *optstr, const char *format)
+{
+   UInt4   flag = 0;
+
+   if (!format)
+   {
+       if ('0' == *optstr)
+       {
+           switch (optstr[1])
+           {
+               case '\0':
+                   format = dec_format;
+                   break;
+               case 'x':
+               case 'X':
+                   optstr += 2;
+                   format = hex_format;
+                   break;
+               default:
+                   format = octal_format;
+                   break;
+           }
+       }
+       else
+           format = dec_format;
+   }
+       
+   if (sscanf(optstr, format, &flag) < 1)
+       return FALSE;
+   replaceExtraOptions(ci, flag, TRUE);
+   return TRUE;
+}
+UInt4  add_removeExtraOptions(ConnInfo *ci, UInt4 aflag, UInt4 dflag)
+{
+   if (0 != (aflag & BIT_FORCEABBREVCONNSTR))
+       ci->force_abbrev_connstr = TRUE;
+   if (0 != (aflag & BIT_FAKE_MSS))
+       ci->fake_mss = TRUE;
+   if (0 != (aflag & BIT_BDE_ENVIRONMENT))
+       ci->bde_environment = TRUE;
+   if (0 != (dflag & BIT_FORCEABBREVCONNSTR))
+       ci->force_abbrev_connstr = FALSE;
+   if (0 != (dflag & BIT_FAKE_MSS))
+       ci->fake_mss =FALSE;
+   if (0 != (dflag & BIT_BDE_ENVIRONMENT))
+       ci->bde_environment = FALSE;
+
+   return getExtraOptions(ci);
+}
+
 void
 makeConnectString(char *connect_string, const ConnInfo *ci, UWORD len)
 {
@@ -36,7 +114,8 @@ makeConnectString(char *connect_string, const ConnInfo *ci, UWORD len)
    char        encoded_conn_settings[LARGE_REGISTRY_LEN];
    Int4        hlen, nlen, olen;
    /*BOOL      abbrev = (len <= 400);*/
-   BOOL        abbrev = (len < 1024) || ci->force_abbrev_connstr;
+   BOOL        abbrev = (len < 1024) || 0 < ci->force_abbrev_connstr;
+   UInt4       flag;
 
 inolog("force_abbrev=%d abbrev=%d\n", ci->force_abbrev_connstr, abbrev);
    /* fundamental info */
@@ -145,7 +224,7 @@ inolog("hlen=%d", hlen);
    /* Abbrebiation is needed ? */
    if (abbrev || olen >= nlen || olen < 0)
    {
-       UInt4 long flag = 0;
+       flag = 0;
        if (ci->disallow_premature)
            flag |= BIT_DISALLOWPREMATURE;
        if (ci->allow_keyset)
@@ -247,9 +326,21 @@ inolog("hlen=%d", hlen);
                ABBR_PROTOCOL "=%s",
                ci->protocol);
        }
-       if (olen < 0 || olen >= nlen) /* failed */
-           connect_string[0] = '\0';
    }
+   if (olen < nlen)
+   {
+       flag = getExtraOptions(ci);
+       if (0 != flag)
+       {
+           hlen = strlen(connect_string);
+           nlen = MAX_CONNECT_STRING - hlen;
+           olen = snprintf(&connect_string[hlen], nlen, ";"
+               INI_EXTRAOPTIONS "=%lx;",
+               flag);
+       }
+   }
+   if (olen < 0 || olen >= nlen) /* failed */
+       connect_string[0] = '\0';
 }
 
 static void
@@ -418,10 +509,24 @@ copyAttributes(ConnInfo *ci, const char *attribute, const char *value)
    else if (stricmp(attribute, INI_XAOPT) == 0)
        ci->xa_opt = atoi(value);
 #endif /* _HANDLE_ENLIST_IN_DTC_ */
-   else if (stricmp(attribute, INI_FORCEABBREVCONNSTR) == 0)
+   else if (stricmp(attribute, INI_EXTRAOPTIONS) == 0)
    {
-       ci->force_abbrev_connstr = atoi(value) & 1;
-       ci->bde_environment = atoi(value) & 2;
+       UInt4   val1 = 0, val2 = 0;
+   
+       if ('+' == value[0])
+       {
+           sscanf(value + 1, "%x-%x", &val1, &val2);
+           add_removeExtraOptions(ci, val1, val2);
+       }
+       else if ('-' == value[0])
+       {
+           sscanf(value + 1, "%x", &val2);
+           add_removeExtraOptions(ci, 0, val2);
+       }
+       else
+       {
+           setExtraOptions(ci, value, hex_format);
+       }
        mylog("force_abbrev=%d bde=%d\n", ci->force_abbrev_connstr, ci->bde_environment);
    }
 
@@ -535,6 +640,12 @@ getDSNdefaults(ConnInfo *ci)
        ci->lower_case_identifier = DEFAULT_LOWERCASEIDENTIFIER;
    if (ci->sslmode[0] == '\0')
        strcpy(ci->sslmode, DEFAULT_SSLMODE);
+   if (ci->force_abbrev_connstr < 0)
+       ci->force_abbrev_connstr = 0;
+   if (ci->fake_mss < 0)
+       ci->fake_mss = 0;
+   if (ci->bde_environment < 0)
+       ci->bde_environment = 0;
 #ifdef _HANDLE_ENLIST_IN_DTC_
    if (ci->xa_opt < 0)
        ci->xa_opt = DEFAULT_XAOPT;
@@ -710,16 +821,15 @@ getDSNinfo(ConnInfo *ci, char overwrite)
 #endif /* _HANDLE_ENLIST_IN_DTC_ */
 
    /* Force abbrev connstr or bde */
-   if (1 || overwrite)
-   {
-       SQLGetPrivateProfileString(DSN, INI_FORCEABBREVCONNSTR, "",
+   SQLGetPrivateProfileString(DSN, INI_EXTRAOPTIONS, "",
                    temp, sizeof(temp), ODBC_INI);
-       if (temp[0])
-       {
-           ci->force_abbrev_connstr = atoi(temp) & 1;
-           ci->bde_environment = atoi(temp) & 2;
-           mylog("force_abbrev=%d bde=%d\n", ci->force_abbrev_connstr, ci->bde_environment);
-       }
+   if (temp[0])
+   {
+       UInt4   val = 0;
+
+       sscanf(temp, "%x", &val);
+       replaceExtraOptions(ci, val, overwrite);
+       mylog("force_abbrev=%d bde=%d\n", ci->force_abbrev_connstr, ci->bde_environment);
    }
 
    /* Allow override of odbcinst.ini parameters here */
@@ -939,6 +1049,11 @@ writeDSNinfo(const ConnInfo *ci)
                                 INI_INT8AS,
                                 temp,
                                 ODBC_INI);
+   sprintf(temp, "%lx", getExtraOptions(ci));
+   SQLWritePrivateProfileString(DSN,
+                           INI_EXTRAOPTIONS,
+                            temp,
+                            ODBC_INI);
    sprintf(temp, "%d", ci->bytea_as_longvarbinary);
    SQLWritePrivateProfileString(DSN,
                                 INI_BYTEAASLONGVARBINARY,
index c9f635fe5a1a08ea76f9f5b9715a669994bddb9c..6d40c8bcc9394c334c9017d500b492fa961bdb9c 100644 (file)
@@ -140,7 +140,7 @@ extern "C" {
 #define ABBR_LOWERCASEIDENTIFIER   "C9"
 #define INI_SSLMODE            "SSLmode"
 #define ABBR_SSLMODE           "CA"
-#define INI_FORCEABBREVCONNSTR     "AB"
+#define INI_EXTRAOPTIONS       "AB"
 
 #define    SSLMODE_DISABLE     "disable"
 #define    SSLMODE_ALLOW       "allow"
@@ -182,6 +182,10 @@ const char *GetXaLibPath();
 
 #define EFFECTIVE_BIT_COUNT            27
 
+/* Mask for extra options  */
+#define    BIT_FORCEABBREVCONNSTR          1L
+#define    BIT_FAKE_MSS                (1L << 1)
+#define    BIT_BDE_ENVIRONMENT         (1L << 2)
 
 /* Connection Defaults */
 #define DEFAULT_PORT               "5432"
@@ -269,6 +273,8 @@ void        copyAttributes(ConnInfo *ci, const char *attribute, const char *value);
 void       copyCommonAttributes(ConnInfo *ci, const char *attribute, const char *value);
 int    getDriverNameFromDSN(const char *dsn, char *driver_name, int namelen);
 int     changeDriverNameOfaDSN(const char *dsn, const char *driver_name, DWORD *errcode);
+UInt4  getExtraOptions(const ConnInfo *);
+BOOL   setExtraOptions(ConnInfo *, const char *str, const char *format);
 
 #ifdef __cplusplus
 }
index eb3bc48ec46ee9c2d8d984cf051f9bb74e736fe4..5e57aa3cdb013c3ee49381278596452c95fc7884 100644 (file)
@@ -546,6 +546,8 @@ ds_options2Proc(HWND hdlg,
                default:
                    CheckDlgButton(hdlg, DS_INT8_AS_DEFAULT, 1);
            }
+           sprintf(buf, "0x%x", getExtraOptions(ci));
+           SetDlgItemText(hdlg, DS_EXTRA_OPTIONS, buf);
 
            CheckDlgButton(hdlg, DS_SHOWOIDCOLUMN, atoi(ci->show_oid_column));
            CheckDlgButton(hdlg, DS_FAKEOIDINDEX, atoi(ci->fake_oid_index));
@@ -618,6 +620,8 @@ ds_options2Proc(HWND hdlg,
                    else
                        ci->int8_as = SQL_VARCHAR;
 
+                   GetDlgItemText(hdlg, DS_EXTRA_OPTIONS, buf, sizeof(buf));
+                   setExtraOptions(ci, buf, NULL);
                    sprintf(ci->show_system_tables, "%d", IsDlgButtonChecked(hdlg, DS_SHOWSYSTEMTABLES));
 
                    sprintf(ci->row_versioning, "%d", IsDlgButtonChecked(hdlg, DS_ROWVERSIONING));
index 6db9435eb6526afc5762bb0375b56427878a00f2..901881d0f8d5747aecc78bb0f02e9e4bc83bed8e 100644 (file)
--- a/drvconn.c
+++ b/drvconn.c
@@ -24,7 +24,7 @@
 #include <sys/socket.h>
 #define NEAR
 #else
-#include <winsock.h>
+#include <winsock2.h>
 #endif
 
 #include <string.h>
index ec0c94a43e743506360bb1129d572f92e7bedfa6..9bd3d8d72d6a44cd69f95450809d766c161b0e36 100644 (file)
--- a/execute.c
+++ b/execute.c
@@ -637,6 +637,75 @@ cleanup:
    return ret;
 }
 
+static void
+SetInsertTable(StatementClass *stmt)
+{
+   const char *cmd = stmt->statement, *ptr;
+   ConnectionClass *conn;
+   size_t  len;
+
+   while (isspace((UCHAR) *cmd)) cmd++;
+   if (!*cmd)
+           return;
+   len = 6;
+   if (strnicmp(cmd, "insert", len))
+           return;
+   cmd += len;
+   while (isspace((UCHAR) *(++cmd)));
+   if (!*cmd)
+           return;
+   len = 4;
+   if (strnicmp(cmd, "into", len))
+           return;
+   cmd += len;
+   while (isspace((UCHAR) *(++cmd)));
+   if (!*cmd)
+           return;
+   conn = SC_get_conn(stmt);
+   NULL_THE_NAME(conn->schemaIns);
+   NULL_THE_NAME(conn->tableIns);
+   ptr = NULL;
+   if (IDENTIFIER_QUOTE == *cmd)
+   {
+       if (ptr = strchr(cmd + 1, IDENTIFIER_QUOTE), NULL == ptr)
+           return;
+       if ('.' == ptr[1])
+       {
+           len = ptr - cmd - 1;
+           STRN_TO_NAME(conn->schemaIns, cmd + 1, len);
+           cmd = ptr + 2;
+           ptr = NULL;
+       }
+   }
+   else
+   {
+       if (ptr = strchr(cmd + 1, '.'), NULL != ptr)
+       {
+           len = ptr - cmd - 1;
+           STRN_TO_NAME(conn->schemaIns, cmd, len);
+           cmd = ptr + 1;
+           ptr = NULL; 
+       }
+   }
+   if (IDENTIFIER_QUOTE == *cmd && NULL == ptr)
+   {
+       if (ptr = strchr(cmd + 1, IDENTIFIER_QUOTE), NULL == ptr)
+           return;
+   }
+   if (IDENTIFIER_QUOTE == *cmd)
+   {
+       len = ptr - cmd - 1;
+       STRN_TO_NAME(conn->tableIns, cmd + 1, len);
+   }
+   else
+   {
+       ptr = cmd;
+       while (*ptr && !isspace((UCHAR) *ptr)) ptr++;
+       len = ptr - cmd;
+       STRN_TO_NAME(conn->tableIns, cmd, len);
+   }
+}
+
 /* Execute a prepared SQL statement */
 RETCODE        SQL_API
 PGAPI_Execute(HSTMT hstmt, UWORD flag)
@@ -900,6 +969,15 @@ next_param_row:
    if (!exec_end)
        goto next_param_row;
 cleanup:
+mylog("retval=%d\n", retval);
+   if (STMT_TYPE_INSERT == stmt->statement_type &&
+       CC_fake_mss(conn) &&
+       (SQL_SUCCESS == retval ||
+        SQL_SUCCESS_WITH_INFO == retval)
+      )
+   {
+       SetInsertTable(stmt);
+   }
 #undef return
    if (stmt->internal)
        retval = DiscardStatementSvp(stmt, retval, FALSE);
diff --git a/info.c b/info.c
index 49a3f6469a0dd8797f53838c622d3d0836d089ad..5ecbc4011ad9cdcbb03c8fdc818618d3e94b783f 100644 (file)
--- a/info.c
+++ b/info.c
@@ -139,16 +139,21 @@ PGAPI_GetInfo(
            value = SQL_CB_NON_NULL;
            break;
 
-       case SQL_CONVERT_BIGINT:
        case SQL_CONVERT_INTEGER:
        case SQL_CONVERT_SMALLINT:
        case SQL_CONVERT_TINYINT:
+       case SQL_CONVERT_BIT:
+       case SQL_CONVERT_VARCHAR:       /* ODBC 1.0 */
+           len = sizeof(SQLUINTEGER);
+           value = SQL_CVT_BIT | SQL_CVT_INTEGER;
+mylog("SQL_CONVERT_ mask=%x\n", value);
+           break;
+       case SQL_CONVERT_BIGINT:
        case SQL_CONVERT_DECIMAL:
        case SQL_CONVERT_DOUBLE:
        case SQL_CONVERT_FLOAT:
        case SQL_CONVERT_NUMERIC:
        case SQL_CONVERT_REAL:
-       case SQL_CONVERT_BIT:
        case SQL_CONVERT_DATE:
        case SQL_CONVERT_TIME:
        case SQL_CONVERT_TIMESTAMP:
@@ -157,7 +162,6 @@ PGAPI_GetInfo(
        case SQL_CONVERT_VARBINARY:     /* ODBC 1.0 */
        case SQL_CONVERT_CHAR:
        case SQL_CONVERT_LONGVARCHAR:
-       case SQL_CONVERT_VARCHAR:       /* ODBC 1.0 */
 #ifdef UNICODE_SUPPORT
        case SQL_CONVERT_WCHAR:
        case SQL_CONVERT_WLONGVARCHAR:
@@ -168,8 +172,9 @@ PGAPI_GetInfo(
            break;
 
        case SQL_CONVERT_FUNCTIONS:     /* ODBC 1.0 */
-           len = 4;
-           value = 0;
+           len = sizeof(SQLUINTEGER);
+           value = SQL_FN_CVT_CONVERT;
+mylog("CONVERT_FUNCTIONS=%x\n", value);
            break;
 
        case SQL_CORRELATION_NAME:      /* ODBC 1.0 */
@@ -217,8 +222,10 @@ PGAPI_GetInfo(
            break;
 
        case SQL_DBMS_NAME:     /* ODBC 1.0 */
-           /* p = DBMS_NAME; */
-           p = "PostgreSQL";
+           if (CC_fake_mss(conn))
+               p = "Microsoft SQL Server";
+           else
+               p = "PostgreSQL";
            break;
 
        case SQL_DBMS_VER:      /* ODBC 1.0 */
@@ -231,8 +238,13 @@ PGAPI_GetInfo(
            /*
            snprintf(tmp, sizeof(tmp) - 1, "%s %s", POSTGRESDRIVERVERSION, conn->pg_version);
                         tmp[sizeof(tmp) - 1] = '\0'; */
-           strncpy_null(tmp, conn->pg_version, sizeof(tmp));
-           p = tmp;
+           if (CC_fake_mss(conn))
+               p = "09.00.1399";
+           else
+           {
+               strncpy_null(tmp, conn->pg_version, sizeof(tmp));
+               p = tmp;
+           }
            break;
 
        case SQL_DEFAULT_TXN_ISOLATION: /* ODBC 1.0 */
@@ -820,6 +832,7 @@ PGAPI_GetTypeInfo(
 {
    CSTR func = "PGAPI_GetTypeInfo";
    StatementClass *stmt = (StatementClass *) hstmt;
+   ConnectionClass *conn;
    QResultClass    *res;
    TupleField  *tuple;
    int         i, result_cols;
@@ -834,6 +847,7 @@ PGAPI_GetTypeInfo(
    if (result = SC_initialize_and_recycle(stmt), SQL_SUCCESS != result)
        return result;
 
+   conn = SC_get_conn(stmt);
    if (res = QR_Constructor(), !res)
    {
        SC_set_error(stmt, STMT_INTERNAL_ERROR, "Error creating result.", func);
@@ -879,30 +893,39 @@ PGAPI_GetTypeInfo(
 
 if (sqlType == SQL_LONGVARBINARY)
 {
-ConnInfo   *ci = &(SC_get_conn(stmt)->connInfo);
+ConnInfo   *ci = &(conn->connInfo);
 inolog("%d sqltype=%d -> pgtype=%d\n", ci->bytea_as_longvarbinary, sqlType, pgType);
 }
 
        if (fSqlType == SQL_ALL_TYPES || fSqlType == sqlType)
        {
-           int pgtcount = 1, cnt;
+           int pgtcount = 1, aunq_match = -1, cnt;
 
-           if (SQL_INTEGER == sqlType && PG_VERSION_GE(SC_get_conn(stmt), 6.4))
-               pgtcount = 2;
+           /*if (SQL_INTEGER == sqlType || SQL_TINYINT == sqlType)*/
+           if (SQL_INTEGER == sqlType)
+           {
+mylog("sqlType=%d ms_jet=%d\n", sqlType, conn->ms_jet);
+               if (conn->ms_jet && PG_VERSION_GE(conn, 6.4))
+               {
+                   aunq_match = 0;
+                   pgtcount = 2;
+               }
+mylog("aunq_match=%d pgtcount=%d\n", aunq_match, pgtcount);
+           }
            for (cnt = 0; cnt < pgtcount; cnt ++)
            {
                tuple = QR_AddNew(res);
 
                /* These values can't be NULL */
-               if (1 == cnt)
+               if (aunq_match == cnt)
                {
-                   set_tuplefield_string(&tuple[0], "serial");
+                   set_tuplefield_string(&tuple[0], pgtype_to_name(stmt, pgType, TRUE));
                    set_tuplefield_int2(&tuple[6], SQL_NO_NULLS);
 inolog("serial in\n");
                }
                else
                {
-                   set_tuplefield_string(&tuple[0], pgtype_to_name(stmt, pgType));
+                   set_tuplefield_string(&tuple[0], pgtype_to_name(stmt, pgType, FALSE));
                    set_tuplefield_int2(&tuple[6], pgtype_nullable(stmt, pgType));
                }
                set_tuplefield_int2(&tuple[1], (Int2) sqlType);
@@ -921,16 +944,14 @@ inolog("serial in\n");
                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));
-               if (1 == cnt)
-               {
-                   set_nullfield_int2(&tuple[9], TRUE);
-                   set_nullfield_int2(&tuple[11], TRUE);
-               }
+               if (1 < pgtcount)
+                   set_tuplefield_int2(&tuple[9], SQL_TRUE);
                else
-               {
                    set_nullfield_int2(&tuple[9], pgtype_unsigned(stmt, 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));
 #if (ODBCVER >=0x0300)
@@ -2271,7 +2292,28 @@ mylog(" and the data=%s\n", attdef);
            set_tuplefield_string(&tuple[COLUMNS_SCHEMA_NAME], "");
        set_tuplefield_string(&tuple[COLUMNS_TABLE_NAME], table_name);
        set_tuplefield_string(&tuple[COLUMNS_COLUMN_NAME], field_name);
-       set_tuplefield_string(&tuple[COLUMNS_TYPE_NAME], field_type_name);
+       auto_unique = SQL_FALSE;
+       switch (field_type)
+       {
+           case PG_TYPE_INT4:
+           case PG_TYPE_INT8:
+               if (attdef && strnicmp(attdef, "nextval(", 8) == 0 &&
+                   not_null[0] == '1')
+               {
+                   auto_unique = SQL_TRUE;
+                   if (CC_fake_mss(conn))
+                   {
+                       char    tmp[32];
+
+                       snprintf(tmp, sizeof(tmp), "%s identity", field_type_name);
+                       set_tuplefield_string(&tuple[COLUMNS_TYPE_NAME], tmp);
+                       break;
+                   }
+               }
+           default:
+               set_tuplefield_string(&tuple[COLUMNS_TYPE_NAME], field_type_name);
+               break;
+       }
 
        /*----------
         * Some Notes about Postgres Data Types:
@@ -2399,14 +2441,6 @@ mylog(" and the data=%s\n", attdef);
        set_tuplefield_null(&tuple[COLUMNS_IS_NULLABLE]);
 #endif /* ODBCVER */
        set_tuplefield_int4(&tuple[COLUMNS_FIELD_TYPE], field_type);
-       auto_unique = FALSE;
-       switch (field_type)
-       {
-           case PG_TYPE_INT4:
-           case PG_TYPE_INT8:
-               if (attdef && strnicmp(attdef, "nextval(", 8) == 0) 
-                   auto_unique = TRUE;
-       }
        set_tuplefield_int4(&tuple[COLUMNS_AUTO_INCREMENT], auto_unique);
        set_tuplefield_int2(&tuple[COLUMNS_PHYSICAL_NUMBER], field_number);
        set_tuplefield_int4(&tuple[COLUMNS_TABLE_OID], greloid);
@@ -2442,7 +2476,7 @@ 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));
+       set_tuplefield_string(&tuple[COLUMNS_TYPE_NAME], pgtype_to_name(stmt, the_type, FALSE));
        set_tuplefield_int4(&tuple[COLUMNS_PRECISION], pgtype_column_size(stmt, the_type, PG_STATIC, PG_STATIC));
        set_tuplefield_int4(&tuple[COLUMNS_LENGTH], pgtype_buffer_length(stmt, the_type, PG_STATIC, PG_STATIC));
        set_nullfield_int2(&tuple[COLUMNS_SCALE], pgtype_decimal_digits(stmt, the_type, PG_STATIC));
@@ -2688,7 +2722,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));
+           set_tuplefield_string(&tuple[3], pgtype_to_name(stmt, the_type, FALSE));
            set_tuplefield_int4(&tuple[4], pgtype_column_size(stmt, the_type, PG_STATIC, PG_STATIC));
            set_tuplefield_int4(&tuple[5], pgtype_buffer_length(stmt, the_type, PG_STATIC, PG_STATIC));
            set_tuplefield_int2(&tuple[6], pgtype_decimal_digits(stmt, the_type, PG_STATIC));
@@ -2712,7 +2746,7 @@ inolog("Add ctid\n");
            set_tuplefield_int2(&tuple[0], SQL_SCOPE_SESSION);
            set_tuplefield_string(&tuple[1], "oid");
            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));
+           set_tuplefield_string(&tuple[3], pgtype_to_name(stmt, the_type, TRUE));
            set_tuplefield_int4(&tuple[4], pgtype_column_size(stmt, the_type, PG_STATIC, PG_STATIC));
            set_tuplefield_int4(&tuple[5], pgtype_buffer_length(stmt, the_type, PG_STATIC, PG_STATIC));
            set_tuplefield_int2(&tuple[6], pgtype_decimal_digits(stmt, the_type, PG_STATIC));
@@ -2729,7 +2763,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));
+               set_tuplefield_string(&tuple[3], pgtype_to_name(stmt, the_type, FALSE));
                set_tuplefield_int4(&tuple[4], pgtype_column_size(stmt, the_type, PG_STATIC, PG_STATIC));
                set_tuplefield_int4(&tuple[5], pgtype_buffer_length(stmt, the_type, PG_STATIC, PG_STATIC));
                set_tuplefield_int2(&tuple[6], pgtype_decimal_digits(stmt, the_type, PG_STATIC));
@@ -4730,7 +4764,7 @@ mylog("atttypid=%s\n", atttypid ? atttypid : "(null)");
                set_tuplefield_string(&tuple[3], "");
                set_tuplefield_int2(&tuple[4], SQL_RETURN_VALUE);
                set_tuplefield_int2(&tuple[5], pgtype_to_concise_type(stmt, pgtype, PG_STATIC));
-               set_tuplefield_string(&tuple[6], pgtype_to_name(stmt, pgtype));
+               set_tuplefield_string(&tuple[6], pgtype_to_name(stmt, pgtype, FALSE));
                set_nullfield_int4(&tuple[7], pgtype_column_size(stmt, pgtype, PG_STATIC, PG_STATIC));
                set_tuplefield_int4(&tuple[8], pgtype_buffer_length(stmt, pgtype, PG_STATIC, PG_STATIC));
                set_nullfield_int2(&tuple[9], pgtype_decimal_digits(stmt, pgtype, PG_STATIC));
@@ -4855,7 +4889,7 @@ mylog("atttypid=%s\n", atttypid ? atttypid : "(null)");
                else
                    set_tuplefield_int2(&tuple[4], SQL_PARAM_INPUT);
                set_tuplefield_int2(&tuple[5], pgtype_to_concise_type(stmt, pgtype, PG_STATIC));
-               set_tuplefield_string(&tuple[6], pgtype_to_name(stmt, pgtype));
+               set_tuplefield_string(&tuple[6], pgtype_to_name(stmt, pgtype, FALSE));
                set_nullfield_int4(&tuple[7], pgtype_column_size(stmt, pgtype, PG_STATIC, PG_STATIC));
                set_tuplefield_int4(&tuple[8], pgtype_buffer_length(stmt, pgtype, PG_STATIC, PG_STATIC));
                set_nullfield_int2(&tuple[9], pgtype_decimal_digits(stmt, pgtype, PG_STATIC));
@@ -4885,7 +4919,7 @@ mylog("atttypid=%s\n", atttypid ? atttypid : "(null)");
            set_tuplefield_string(&tuple[3], attname);
            set_tuplefield_int2(&tuple[4], SQL_RESULT_COL);
            set_tuplefield_int2(&tuple[5], pgtype_to_concise_type(stmt, typid, PG_STATIC));
-           set_tuplefield_string(&tuple[6], pgtype_to_name(stmt, typid));
+           set_tuplefield_string(&tuple[6], pgtype_to_name(stmt, typid, FALSE));
            set_nullfield_int4(&tuple[7], pgtype_column_size(stmt, typid, PG_STATIC, PG_STATIC));
            set_tuplefield_int4(&tuple[8], pgtype_buffer_length(stmt, typid, PG_STATIC, PG_STATIC));
            set_nullfield_int2(&tuple[9], pgtype_decimal_digits(stmt, typid, PG_STATIC));
index 5a9c0870305ad44ba612cde1a5b9cfd8b756f65f..d010ada13cdf2925313f7dd0e363eef3a8b6f481 100644 (file)
 */
 #include   "misc.h"
 #include   <malloc.h>
+#ifdef _DEBUG
+#include   <stdlib.h>
+#define    _CRTDBG_MAP_ALLOC
+#include <crtdbg.h>
+#endif /* _DEBUG */
 #include   <string.h>
 
 typedef struct {
@@ -250,6 +255,8 @@ void debug_memory_check(void)
    if (0 == tbsize)
    {
        mylog("no memry leak found and max count allocated so far is %d\n", alsize);
+       free(altbl);
+       alsize = 0;
    }
    else
    {
diff --git a/misc.h b/misc.h
index eecf0549de789124c8b58466b01eb3263301aee0..d786f303fa242954df0225aae3e5d85cbe586ef3 100644 (file)
--- a/misc.h
+++ b/misc.h
@@ -120,6 +120,9 @@ int get_mylog(void);
 #endif
 
 
+void   InitializeLogging();
+void   FinalizeLogging();
+
 void       remove_newlines(char *string);
 char      *strncpy_null(char *dst, const char *src, int len);
 char      *trim(char *string);
index d54111bfe2cd6ee4e6a2261650a12dd2cb6aa969..f8e1ebac3c435b33d11c2b6c687a6493eb46f4d7 100755 (executable)
@@ -12,6 +12,7 @@
 #define    _WIN32_WINNT    0x0400
 #endif /* _WIN32_WINNT */
 
+#define    WIN32_LEAN_AND_MEAN
 #include <oleTx2xa.h>
 #include <XOLEHLP.h>
 /*#include <Txdtc.h>*/
@@ -962,7 +963,7 @@ mylog("dllname=%s dsn=%s\n", xalibname, conn->connInfo.dsn); res = 0;
    ConnInfo *ci = &(conn->connInfo);
    char    dtcname[1024];
    snprintf(dtcname, sizeof(dtcname), "DRIVER={%s};SERVER=%s;PORT=%s;DATABASE=%s;UID=%s;PWD=%s;" ABBR_SSLMODE "=%s", 
-       ci->drivername, ci->server, ci->port, ci->database, ci->username, ci->password, ci->sslmode, ci->drivers.debug);
+       ci->drivername, ci->server, ci->port, ci->database, ci->username, ci->password, ci->sslmode);
    do { 
        res = pHelper->XARMCreate(dtcname, (char *) GetXaLibName(), &dwRMCookie);
        if (S_OK == res)
diff --git a/mylog.c b/mylog.c
index 6a9a1be93ef56fc2c2c2d7e3858a89938b88e892..7bacb310ca9ed497741fa69560dc1f7ada40dda2 100644 (file)
--- a/mylog.c
+++ b/mylog.c
@@ -58,9 +58,9 @@ generate_filename(const char *dirname, const char *prefix, char *filename)
 }
 
 #if defined(WIN_MULTITHREAD_SUPPORT)
-CRITICAL_SECTION   qlog_cs, mylog_cs;
+static CRITICAL_SECTION    qlog_cs, mylog_cs;
 #elif defined(POSIX_MULTITHREAD_SUPPORT)
-pthread_mutex_t    qlog_cs, mylog_cs;
+static pthread_mutex_t qlog_cs, mylog_cs;
 #endif /* WIN_MULTITHREAD_SUPPORT */
 static int mylog_on = 0, qlog_on = 0;
 
@@ -113,7 +113,7 @@ logs_on_off(int cnopen, int mylog_onoff, int qlog_onoff)
 }
 
 #ifdef MY_LOG
-static FILE *LOGFP = NULL;
+static FILE *MLOGFP = NULL;
 void
 mylog(char *fmt,...)
 {
@@ -125,26 +125,26 @@ mylog(char *fmt,...)
    {
        va_start(args, fmt);
 
-       if (!LOGFP)
+       if (!MLOGFP)
        {
            generate_filename(MYLOGDIR, MYLOGFILE, filebuf);
-           LOGFP = fopen(filebuf, PG_BINARY_A);
-           if (LOGFP)
-               setbuf(LOGFP, NULL);
+           MLOGFP = fopen(filebuf, PG_BINARY_A);
+           if (MLOGFP)
+               setbuf(MLOGFP, NULL);
        }
 
 #ifdef WIN_MULTITHREAD_SUPPORT
 #ifdef WIN32
-       if (LOGFP)
-           fprintf(LOGFP, "[%d]", GetCurrentThreadId());
+       if (MLOGFP)
+           fprintf(MLOGFP, "[%d]", GetCurrentThreadId());
 #endif /* WIN32 */
 #endif /* WIN_MULTITHREAD_SUPPORT */
 #if defined(POSIX_MULTITHREAD_SUPPORT)
-       if (LOGFP)
-           fprintf(LOGFP, "[%d]", pthread_self());
+       if (MLOGFP)
+           fprintf(MLOGFP, "[%d]", pthread_self());
 #endif /* POSIX_MULTITHREAD_SUPPORT */
-       if (LOGFP)
-           vfprintf(LOGFP, fmt, args);
+       if (MLOGFP)
+           vfprintf(MLOGFP, fmt, args);
 
        va_end(args);
    }
@@ -159,21 +159,21 @@ forcelog(const char *fmt,...)
    ENTER_MYLOG_CS;
    va_start(args, fmt);
 
-   if (!LOGFP)
+   if (!MLOGFP)
    {
        generate_filename(MYLOGDIR, MYLOGFILE, filebuf);
-       LOGFP = fopen(filebuf, PG_BINARY_A);
-       if (LOGFP)
-           setbuf(LOGFP, NULL);
+       MLOGFP = fopen(filebuf, PG_BINARY_A);
+       if (MLOGFP)
+           setbuf(MLOGFP, NULL);
    }
-   if (!LOGFP)
+   if (!MLOGFP)
    {
        generate_filename("C:\\podbclog", MYLOGFILE, filebuf);
-       LOGFP = fopen(filebuf, PG_BINARY_A);
-       if (LOGFP)
-           setbuf(LOGFP, NULL);
+       MLOGFP = fopen(filebuf, PG_BINARY_A);
+       if (MLOGFP)
+           setbuf(MLOGFP, NULL);
    }
-   if (LOGFP)
+   if (MLOGFP)
    {
 #ifdef WIN_MULTITHREAD_SUPPORT
 #ifdef WIN32
@@ -183,51 +183,94 @@ forcelog(const char *fmt,...)
        time(&ntime);
        strcpy(ctim, ctime(&ntime));
        ctim[strlen(ctim) - 1] = '\0';
-       fprintf(LOGFP, "[%d.%d(%s)]", GetCurrentProcessId(), GetCurrentThreadId(), ctim);
+       fprintf(MLOGFP, "[%d.%d(%s)]", GetCurrentProcessId(), GetCurrentThreadId(), ctim);
 #endif /* WIN32 */
 #endif /* WIN_MULTITHREAD_SUPPORT */
 #if defined(POSIX_MULTITHREAD_SUPPORT)
-       fprintf(LOGFP, "[%d]", pthread_self());
+       fprintf(MLOGFP, "[%d]", pthread_self());
 #endif /* POSIX_MULTITHREAD_SUPPORT */
-       vfprintf(LOGFP, fmt, args);
+       vfprintf(MLOGFP, fmt, args);
    }
    va_end(args);
    LEAVE_MYLOG_CS;
 }
+static void mylog_initialize()
+{
+   INIT_MYLOG_CS;
+}
+static void mylog_finalize()
+{
+   if (MLOGFP)
+   {
+       fclose(MLOGFP);
+       MLOGFP = NULL;
+   }
+   DELETE_MYLOG_CS;
+}
 #else
 void
 MyLog(char *fmt,...)
 {
 }
-#endif
+static void mylog_initialize() {}
+static void mylog_finalize() {}
+#endif /* MY_LOG */
 
 
 #ifdef Q_LOG
+static FILE *QLOGFP = NULL;
 void
 qlog(char *fmt,...)
 {
    va_list     args;
    char        filebuf[80];
-   static FILE *LOGFP = NULL;
 
    ENTER_QLOG_CS;
    if (qlog_on)
    {
        va_start(args, fmt);
 
-       if (!LOGFP)
+       if (!QLOGFP)
        {
            generate_filename(QLOGDIR, QLOGFILE, filebuf);
-           LOGFP = fopen(filebuf, PG_BINARY_A);
-           if (LOGFP)
-               setbuf(LOGFP, NULL);
+           QLOGFP = fopen(filebuf, PG_BINARY_A);
+           if (QLOGFP)
+               setbuf(QLOGFP, NULL);
        }
 
-       if (LOGFP)
-           vfprintf(LOGFP, fmt, args);
+       if (QLOGFP)
+           vfprintf(QLOGFP, fmt, args);
 
        va_end(args);
    }
    LEAVE_QLOG_CS;
 }
-#endif
+static void qlog_initialize()
+{
+   INIT_QLOG_CS;
+}
+static void qlog_finalize()
+{
+   if (QLOGFP)
+   {
+       fclose(QLOGFP);
+       QLOGFP = NULL;
+   }
+   DELETE_QLOG_CS;
+}
+#else
+static void qlog_initialize() {}
+static void qlog_finalize() {}
+#endif /* Q_LOG */
+
+void InitializeLogging()
+{
+   mylog_initialize();
+   qlog_initialize();
+}
+
+void FinalizeLogging()
+{
+   mylog_finalize();
+   qlog_finalize();
+}
index ac1f6710e0233ffb41075aec6a803c30574466ff..e5d798a3e663cb4bf49a2c4a00c1ae0c2d0d46d1 100644 (file)
@@ -116,7 +116,7 @@ RETCODE SQL_API SQLDriverConnectW(HDBC hdbc,
    CSTR func = "SQLDriverConnectW";
    char    *szIn, *szOut = NULL;
    Int4    maxlen, inlen, obuflen = 0;
-   SQLSMALLINT olen;
+   SQLSMALLINT olen, *pCSO;
    RETCODE ret;
    ConnectionClass *conn = (ConnectionClass *) hdbc;
 
@@ -126,14 +126,19 @@ RETCODE SQL_API SQLDriverConnectW(HDBC hdbc,
    CC_set_in_unicode_driver(conn);
    szIn = ucs2_to_utf8(szConnStrIn, cbConnStrIn, &inlen, FALSE);
    maxlen = cbConnStrOutMax;
+   pCSO = NULL;
+   olen = 0;
    if (maxlen > 0)
    {
        obuflen = maxlen + 1;
        szOut = malloc(obuflen);
+       pCSO = &olen;
    }
+   else if (pcbConnStrOut)
+       pCSO = &olen;
    ret = PGAPI_DriverConnect(hdbc, hwnd, szIn, (SQLSMALLINT) inlen,
-       szOut, maxlen, &olen, fDriverCompletion);
-   if (ret != SQL_ERROR)
+       szOut, maxlen, pCSO, fDriverCompletion);
+   if (ret != SQL_ERROR && NULL != pCSO)
    {
        UInt4 outlen = olen;
 
@@ -141,10 +146,9 @@ RETCODE SQL_API SQLDriverConnectW(HDBC hdbc,
            outlen = utf8_to_ucs2(szOut, olen, szConnStrOut, cbConnStrOutMax);
        else
            utf8_to_ucs2(szOut, maxlen, szConnStrOut, cbConnStrOutMax);
-       if (0 == cbConnStrOutMax && NULL == pcbConnStrOut)
-           ;
-       else if (outlen >= (UInt4) cbConnStrOutMax)
+       if (outlen >= (UInt4) cbConnStrOutMax)
        {
+inolog("cbConnstrOutMax=%d pcb=%x\n", cbConnStrOutMax, pcbConnStrOut);
            if (SQL_SUCCESS == ret)
            {
                CC_set_error(conn, CONN_TRUNCATED, "the ConnStrOut is too small", func);
@@ -671,7 +675,7 @@ RETCODE SQL_API SQLNativeSqlW(
 {
    CSTR func = "SQLNativeSqlW";
    RETCODE     ret;
-   char        *szIn, *szOut;
+   char        *szIn, *szOut = NULL;
    Int4        slen;
    SQLINTEGER  buflen, olen;
    ConnectionClass *conn = (ConnectionClass *) hdbc;
@@ -681,13 +685,14 @@ RETCODE SQL_API SQLNativeSqlW(
    CC_clear_error(conn);
    CC_set_in_unicode_driver(conn);
    szIn = ucs2_to_utf8(szSqlStrIn, cbSqlStrIn, &slen, FALSE);
-   buflen = 3 * cbSqlStrMax + 1;
-   szOut = malloc(buflen);
+   buflen = 3 * cbSqlStrMax;
+   if (buflen > 0)
+       szOut = malloc(buflen);
    for (;; buflen = olen + 1, szOut = realloc(szOut, buflen))
    {
        ret = PGAPI_NativeSql(hdbc, szIn, (SQLINTEGER) slen,
            szOut, buflen, &olen);
-       if (SQL_SUCCESS_WITH_INFO == ret || olen < buflen)
+       if (SQL_SUCCESS_WITH_INFO != ret || olen < buflen)
            break;
    }
    if (szIn)
index cdc5b13e4bc85f243c6e39adba5b5d33f3ae2477..e13dfc8099b0c97eb5224f199a75a90f62d59471 100644 (file)
--- a/options.c
+++ b/options.c
@@ -379,7 +379,8 @@ PGAPI_SetConnectOption(
        case SQL_CURRENT_QUALIFIER:     /* ignored */
            break;
 
-       case SQL_LOGIN_TIMEOUT: /* ignored */
+       case SQL_LOGIN_TIMEOUT:
+           conn->login_timeout = vParam;
            break;
 
        case SQL_PACKET_SIZE:   /* ignored */
@@ -530,8 +531,8 @@ PGAPI_GetConnectOption(
            p = CurrCatString(conn);
            break;
 
-       case SQL_LOGIN_TIMEOUT: /* NOT SUPPORTED */
-           *((UDWORD *) pvParam) = 0;
+       case SQL_LOGIN_TIMEOUT:
+           *((UDWORD *) pvParam) = conn->login_timeout;
            break;
 
        case SQL_PACKET_SIZE:   /* NOT SUPPORTED */
diff --git a/parse.c b/parse.c
index 008c209f050873057dffa50344f043ae3e598bc2..60d3ea21bb617a1253b32d96754d9909a99cb74b 100644 (file)
--- a/parse.c
+++ b/parse.c
@@ -568,18 +568,105 @@ static BOOL ColAttSet(StatementClass *stmt, TABLE_INFO *rti)
    return TRUE;
 }
 
-BOOL getCOLIfromTI(const char *func, StatementClass *stmt, const Oid reloid, TABLE_INFO **pti)
+static BOOL
+getCOLIfromTable(ConnectionClass *conn, pgNAME *schema_name, pgNAME table_name, 
+COL_INFO **coli)
+{
+   int colidx;
+   BOOL    found = FALSE;
+
+   *coli = NULL;
+   if (NAME_IS_NULL(table_name))
+       return TRUE;
+   if (conn->schema_support)
+   {
+       if (NAME_IS_NULL(*schema_name))
+       {
+           const char *curschema = CC_get_current_schema(conn);
+           /*
+            * Though current_schema() doesn't have
+            * much sense in PostgreSQL, we first
+            * check the current_schema() when no
+            * explicit schema name was specified.
+            */
+           for (colidx = 0; colidx < conn->ntables; colidx++)
+           {
+               if (!NAMEICMP(conn->col_info[colidx]->table_name, table_name) &&
+                   !stricmp(SAFE_NAME(conn->col_info[colidx]->schema_name), curschema))
+               {
+                   mylog("FOUND col_info table='%s' current schema='%s'\n", PRINT_NAME(table_name), curschema);
+                   found = TRUE;
+                   STR_TO_NAME(*schema_name, curschema);
+                   break;
+               }
+           }
+           if (!found)
+           {
+               QResultClass    *res;
+               char        token[256];
+               BOOL        tblFound = FALSE;
+
+               /*
+                * We also have to check as follows.
+                */
+               sprintf(token, "select nspname from pg_namespace n, pg_class c"
+                       " where c.relnamespace=n.oid and c.oid='\"%s\"'::regclass", SAFE_NAME(table_name));
+               res = CC_send_query(conn, token, NULL, ROLLBACK_ON_ERROR | IGNORE_ABORT_ON_CONN, NULL);
+               if (QR_command_maybe_successful(res))
+               {
+                   if (QR_get_num_total_tuples(res) == 1)
+                   {
+                       tblFound = TRUE;
+                       STR_TO_NAME(*schema_name, QR_get_value_backend_row(res, 0, 0));
+                   }
+               }
+               QR_Destructor(res);
+               if (!tblFound)
+                   return FALSE;
+           }
+       }
+       if (!found && NAME_IS_VALID(*schema_name))
+       {
+           for (colidx = 0; colidx < conn->ntables; colidx++)
+           {
+               if (!NAMEICMP(conn->col_info[colidx]->table_name, table_name) &&
+                   !NAMEICMP(conn->col_info[colidx]->schema_name, *schema_name))
+               {
+                   mylog("FOUND col_info table='%s' schema='%s'\n", PRINT_NAME(table_name), PRINT_NAME(*schema_name));
+                   found = TRUE;
+                   break;
+               }
+           }
+       }
+   }
+   else
+   {
+       for (colidx = 0; colidx < conn->ntables; colidx++)
+       {
+           if (!NAMEICMP(conn->col_info[colidx]->table_name, table_name))
+           {
+               mylog("FOUND col_info table='%s'\n", table_name);
+               found = TRUE;
+               break;
+           }
+       }
+   }
+   *coli = found ? conn->col_info[colidx] : NULL;
+   return TRUE; /* success */
+}
+
+BOOL getCOLIfromTI(const char *func, ConnectionClass *conn, StatementClass *stmt, const Oid reloid, TABLE_INFO **pti)
 {
    BOOL    colatt = FALSE, found = FALSE;
-   ConnectionClass *conn = SC_get_conn(stmt);
    Oid greloid = reloid;
-   int colidx;
-   char    token[256];
    TABLE_INFO  *wti = *pti;
+   COL_INFO    *coli;
    HSTMT       hcol_stmt = NULL;
    QResultClass    *res;
 
 inolog("getCOLIfromTI reloid=%u ti=%x\n", reloid, wti);
+   if (!conn)
+       conn = SC_get_conn(stmt);
    if (!wti)   /* SQLColAttribute case */
    {
        int i;
@@ -614,101 +701,39 @@ inolog("fi=%x greloid=%d col_info=%x\n", wti, greloid, wti->col_info);
    }
    if (greloid != 0)
    {
+       int colidx;
+
        for (colidx = 0; colidx < conn->ntables; colidx++)
        {
            if (conn->col_info[colidx]->table_oid == greloid)
            {
                mylog("FOUND col_info table=%ul\n", greloid);
                found = TRUE;
+               wti->col_info = conn->col_info[colidx];
                break;
            }
        }
    }
    else
    {
-       if (conn->schema_support)
+       if (!getCOLIfromTable(conn, &wti->schema_name, wti->table_name, &coli))
        {
-           if (NAME_IS_NULL(wti->schema_name))
-           {
-               const char *curschema = CC_get_current_schema(conn);
-               /*
-                * Though current_schema() doesn't have
-                * much sense in PostgreSQL, we first
-                * check the current_schema() when no
-                * explicit schema name was specified.
-                */
-               for (colidx = 0; colidx < conn->ntables; colidx++)
-               {
-                   if (!NAMEICMP(conn->col_info[colidx]->table_name, wti->table_name) &&
-                       !stricmp(SAFE_NAME(conn->col_info[colidx]->schema_name), curschema))
-                   {
-                       mylog("FOUND col_info table='%s' current schema='%s'\n", PRINT_NAME(wti->table_name), curschema);
-                       found = TRUE;
-                       STR_TO_NAME(wti->schema_name, curschema);
-                       break;
-                   }
-               }
-               if (!found)
-               {
-                   QResultClass    *res;
-                   BOOL        tblFound = FALSE;
-
-                   /*
-                    * We also have to check as follows.
-                    */
-                   sprintf(token, "select nspname from pg_namespace n, pg_class c"
-                       " where c.relnamespace=n.oid and c.oid='\"%s\"'::regclass", SAFE_NAME(wti->table_name));
-                   res = CC_send_query(conn, token, NULL, ROLLBACK_ON_ERROR | IGNORE_ABORT_ON_CONN, NULL);
-                   if (QR_command_maybe_successful(res))
-                   {
-                       if (QR_get_num_total_tuples(res) == 1)
-                       {
-                           tblFound = TRUE;
-                           STR_TO_NAME(wti->schema_name, QR_get_value_backend_row(res, 0, 0));
-                       }
-                   }
-                   QR_Destructor(res);
-                   if (!tblFound)
-                   {
-                       SC_set_parse_status(stmt, STMT_PARSE_FATAL);
-                       SC_set_error(stmt, STMT_EXEC_ERROR, "Table not found", func);
-                       stmt->updatable = FALSE;
-                       return FALSE;
-                   }
-               }
-           }
-           if (!found && NAME_IS_VALID(wti->schema_name))
+           if (stmt)
            {
-               for (colidx = 0; colidx < conn->ntables; colidx++)
-               {
-                   if (!NAMEICMP(conn->col_info[colidx]->table_name, wti->table_name) &&
-                       !NAMEICMP(conn->col_info[colidx]->schema_name, wti->schema_name))
-                   {
-                       mylog("FOUND col_info table='%s' schema='%s'\n", PRINT_NAME(wti->table_name), PRINT_NAME(wti->schema_name));
-                       found = TRUE;
-                       break;
-                   }
-               }
+               SC_set_parse_status(stmt, STMT_PARSE_FATAL);
+               SC_set_error(stmt, STMT_EXEC_ERROR, "Table not found", func);
+               stmt->updatable = FALSE;
            }
+           return FALSE;
        }
-       else
+       else if (NULL != coli)
        {
-           for (colidx = 0; colidx < conn->ntables; colidx++)
-           {
-               if (!NAMEICMP(conn->col_info[colidx]->table_name, wti->table_name))
-               {
-                   mylog("FOUND col_info table='%s'\n", wti->table_name);
-                   found = TRUE;
-                   break;
-               }
-           }
+           found = TRUE;
+           wti->col_info = coli;
        }
    }
    if (found)
-   {
-       wti->col_info = conn->col_info[colidx];
        goto cleanup;
-   }
    else
    {
        RETCODE     result;
@@ -716,10 +741,11 @@ inolog("fi=%x greloid=%d col_info=%x\n", wti, greloid, wti->col_info);
 
        mylog("PARSE: Getting PG_Columns for table='%s'\n", wti->table_name);
 
-       result = PGAPI_AllocStmt(stmt->hdbc, &hcol_stmt);
+       result = PGAPI_AllocStmt(conn, &hcol_stmt);
        if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
        {
-           SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "PGAPI_AllocStmt failed in parse_statement for columns.", func);
+           if (stmt)
+               SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "PGAPI_AllocStmt failed in parse_statement for columns.", func);
            goto cleanup;
        }
 
@@ -754,7 +780,8 @@ inolog("fi=%x greloid=%d col_info=%x\n", wti, greloid, wti->col_info);
                conn->col_info = (COL_INFO **) realloc(conn->col_info, new_alloc * sizeof(COL_INFO *));
                if (!conn->col_info)
                {
-                   SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "PGAPI_AllocStmt failed in parse_statement for col_info.", func);
+                   if (stmt)
+                       SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "PGAPI_AllocStmt failed in parse_statement for col_info.", func);
                    goto cleanup;
                }
                conn->coli_allocated = new_alloc;
@@ -763,8 +790,9 @@ inolog("fi=%x greloid=%d col_info=%x\n", wti, greloid, wti->col_info);
            mylog("PARSE: malloc at conn->col_info[%d]\n", conn->ntables);
            coli = conn->col_info[conn->ntables] = (COL_INFO *) malloc(sizeof(COL_INFO));
            if (!coli)
-           {
-               SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "PGAPI_AllocStmt failed in parse_statement for col_info(2).", func);
+           {   
+               if (stmt)
+                   SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "PGAPI_AllocStmt failed in parse_statement for col_info(2).", func);
                goto cleanup;
            }
            col_info_initialize(coli);
@@ -838,10 +866,11 @@ inolog("#1 %x->table_name=%s(%u)\n", wti, PRINT_NAME(wti->table_name), wti->tabl
        if (colatt /* SQLColAttribute case */
            && 0 == (wti->flags & TI_COLATTRIBUTE))
        {
-           ColAttSet(stmt, wti);
+           if (stmt)
+               ColAttSet(stmt, wti);
        }
    }
-   else if (!colatt)
+   else if (!colatt && stmt)
        SC_set_parse_status(stmt, STMT_PARSE_FATAL);
 inolog("getCOLIfromTI returns %d\n", found);
    return found;
@@ -1446,7 +1475,7 @@ parse_statement(StatementClass *stmt, BOOL check_hasoids)
 
        wti = ti[i];
 
-       if (!getCOLIfromTI(func, stmt, 0, &wti))
+       if (!getCOLIfromTI(func, NULL, stmt, 0, &wti))
            break;
    }
    if (STMT_PARSE_FATAL == SC_parsed_status(stmt))
index 3a433085c0703a9c19e5041b36a40eb42c0f6b96..e8c1583ff3557db454fade8b00fe430d6e9c56a2 100644 (file)
@@ -128,7 +128,7 @@ RETCODE SQL_API PGAPI_PutData(HSTMT StatementHandle,
 RETCODE SQL_API PGAPI_RowCount(HSTMT StatementHandle,
               SQLLEN *RowCount);
 RETCODE SQL_API PGAPI_SetConnectOption(HDBC ConnectionHandle,
-                      SQLUSMALLINT Option, SQLUINTEGER Value);
+                      SQLUSMALLINT Option, SQLULEN Value);
 RETCODE SQL_API PGAPI_SetCursorName(HSTMT StatementHandle,
                    const SQLCHAR *CursorName, SQLSMALLINT NameLength);
 RETCODE SQL_API PGAPI_SetParam(HSTMT StatementHandle,
index cdb3c667afcb5e6399ac4ca5b9438b23ea846175..f87a7b28717463a8a9bdf444185c3846f923f6b3 100644 (file)
--- a/pgtypes.c
+++ b/pgtypes.c
@@ -42,35 +42,35 @@ Int4        getCharColumnSize(StatementClass *stmt, Int4 type, int col, int handle_unk
  */
 
 /*
-Int4 pgtypes_defined[] = {
-               PG_TYPE_CHAR,
-               PG_TYPE_CHAR2,
-               PG_TYPE_CHAR4,
-               PG_TYPE_CHAR8,
-               PG_TYPE_CHAR16,
-               PG_TYPE_NAME,
-               PG_TYPE_VARCHAR,
-               PG_TYPE_BPCHAR,
-               PG_TYPE_DATE,
-               PG_TYPE_TIME,
-               PG_TYPE_TIME_WITH_TMZONE,
-               PG_TYPE_DATETIME,
-               PG_TYPE_ABSTIME,
-               PG_TYPE_TIMESTAMP_NO_TMZONE,
-               PG_TYPE_TIMESTAMP,
-               PG_TYPE_TEXT,
-               PG_TYPE_INT2,
-               PG_TYPE_INT4,
-               PG_TYPE_FLOAT4,
-               PG_TYPE_FLOAT8,
-               PG_TYPE_OID,
-               PG_TYPE_MONEY,
-               PG_TYPE_BOOL,
-               PG_TYPE_BYTEA,
-               PG_TYPE_NUMERIC,
-               PG_TYPE_XID,
-               PG_TYPE_LO_UNDEFINED,
-               0 };
+Int4 pgtypes_defined[][2] = {
+           {PG_TYPE_CHAR, 0}
+           ,{PG_TYPE_CHAR2, 0}
+           ,{PG_TYPE_CHAR4, 0}
+           ,{PG_TYPE_CHAR8, 0}
+           ,{PG_TYPE_CHAR16, 0}
+           ,{PG_TYPE_NAME, 0}
+           ,{PG_TYPE_VARCHAR, 0}
+           ,{PG_TYPE_BPCHAR, 0}
+           ,{PG_TYPE_DATE, 0}
+           ,{PG_TYPE_TIME, 0}
+           ,{PG_TYPE_TIME_WITH_TMZONE, 0}
+           ,{PG_TYPE_DATETIME, 0}
+           ,{PG_TYPE_ABSTIME, 0}
+           ,{PG_TYPE_TIMESTAMP_NO_TMZONE, 0}
+           ,{PG_TYPE_TIMESTAMP, 0}
+           ,{PG_TYPE_TEXT, 0}
+           ,{PG_TYPE_INT2, 0}
+           ,{PG_TYPE_INT4, 0}
+           ,{PG_TYPE_FLOAT4, 0}
+           ,{PG_TYPE_FLOAT8, 0}
+           ,{PG_TYPE_OID, 0}
+           ,{PG_TYPE_MONEY, 0}
+           ,{PG_TYPE_BOOL, 0}
+           ,{PG_TYPE_BYTEA, 0}
+           ,{PG_TYPE_NUMERIC, 0}
+           ,{PG_TYPE_XID, 0}
+           ,{PG_TYPE_LO_UNDEFINED, 0}
+           ,{0, 0} };
 */
 
 
@@ -502,7 +502,7 @@ pgtype_to_ctype(StatementClass *stmt, Int4 type)
 
 
 const char *
-pgtype_to_name(StatementClass *stmt, Int4 type)
+pgtype_to_name(StatementClass *stmt, Int4 type, BOOL auto_increment)
 {
    ConnectionClass *conn = SC_get_conn(stmt);
    switch (type)
@@ -516,7 +516,7 @@ pgtype_to_name(StatementClass *stmt, Int4 type)
        case PG_TYPE_CHAR8:
            return "char8";
        case PG_TYPE_INT8:
-           return "int8";
+           return auto_increment ? "bigserial" : "int8";
        case PG_TYPE_NUMERIC:
            return "numeric";
        case PG_TYPE_VARCHAR:
@@ -535,7 +535,7 @@ pgtype_to_name(StatementClass *stmt, Int4 type)
            return "xid";
        case PG_TYPE_INT4:
 inolog("pgtype_to_name int4\n");
-           return "int4";
+           return auto_increment ? "serial" : "int4";
        case PG_TYPE_FLOAT4:
            return "float4";
        case PG_TYPE_FLOAT8:
index 73c0e6fd340439ff1515f5abc969364a06c37aa0..c409622b1c89af191bab930032ce41008a7fc89a 100644 (file)
--- a/pgtypes.h
+++ b/pgtypes.h
 /* in table pg_type */
 
 
-#if 0
+#ifdef NOT_USED
 #define PG_TYPE_LO             ????    /* waiting for permanent type */
 #endif
 
+#define    MS_ACCESS_SERIAL        "int identity"
 #define PG_TYPE_BOOL           16
 #define PG_TYPE_BYTEA          17
 #define PG_TYPE_CHAR           18
@@ -82,7 +83,7 @@ Int2      pgtype_to_concise_type(StatementClass *stmt, Int4 type, int col);
 Int2       pgtype_to_sqldesctype(StatementClass *stmt, Int4 type, int col);
 Int2       pgtype_to_datetime_sub(StatementClass *stmt, Int4 type);
 Int2       pgtype_to_ctype(StatementClass *stmt, Int4 type);
-const char *pgtype_to_name(StatementClass *stmt, Int4 type);
+const char *pgtype_to_name(StatementClass *stmt, Int4 type, BOOL auto_increment);
 
 /* These functions can use static numbers or result sets(col parameter) */
 SQLLEN     pgtype_column_size(StatementClass *stmt, Int4 type, int col, int handle_unknown_size_as); /* corresponds to "precision" in ODBC 2.x */
index a001a4f830fe660789d1ddaae696ab2b9588ba0c..bdf77e0f8fe241ca3d0c32421e0f6da0af11c033 100644 (file)
@@ -18,7 +18,7 @@
 #include "environ.h"
 
 #ifdef WIN32
-#include <winsock.h>
+#include <winsock2.h>
 #endif
 
 GLOBAL_VALUES globals;
@@ -26,9 +26,9 @@ GLOBAL_VALUES globals;
 RETCODE SQL_API SQLDummyOrdinal(void);
 
 #if defined(WIN_MULTITHREAD_SUPPORT)
-extern CRITICAL_SECTION    qlog_cs, mylog_cs, conns_cs, common_cs;
+extern CRITICAL_SECTION    conns_cs, common_cs;
 #elif defined(POSIX_MULTITHREAD_SUPPORT)
-extern pthread_mutex_t     qlog_cs, mylog_cs, conns_cs, common_cs;
+extern pthread_mutex_t     conns_cs, common_cs;
 
 #ifdef POSIX_THREADMUTEX_SUPPORT
 #ifdef PG_RECURSIVE_MUTEXATTR
@@ -64,11 +64,15 @@ int initialize_global_cs(void)
    if (!init)
        return 0;
    init = 0;
+#ifdef _DEBUG
+#ifdef _MEMORY_DEBUG_
+   _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF|_CRTDBG_LEAK_CHECK_DF);
+#endif /* _MEMORY_DEBUG_ */
+#endif /* _DEBUG */
 #ifdef POSIX_THREADMUTEX_SUPPORT
    getMutexAttr();
 #endif /* POSIX_THREADMUTEX_SUPPORT */
-   INIT_QLOG_CS;
-   INIT_MYLOG_CS;
+   InitializeLogging();
    INIT_CONNS_CS;
    INIT_COMMON_CS;
 
@@ -79,8 +83,12 @@ static void finalize_global_cs(void)
 {
    DELETE_COMMON_CS;
    DELETE_CONNS_CS;
-   DELETE_QLOG_CS;
-   DELETE_MYLOG_CS;
+   FinalizeLogging();
+#ifdef _DEBUG
+#ifdef _MEMORY_DEBUG_
+   // _CrtDumpMemoryLeaks();
+#endif /* _MEMORY_DEBUG_ */
+#endif /* _DEBUG */
 }
 
 #ifdef WIN32
index 96b2f6e94e55c56f9ce7005d8f24849e39e50b42..4a2df1d02f832fc3f005de968457dd5db5715a0e 100644 (file)
@@ -5,7 +5,7 @@
  *
  * Comments:       See "notice.txt" for copyright and license information.
  *
- * $Id: psqlodbc.h,v 1.102 2006/06/15 06:58:49 luf Exp $
+ * $Id: psqlodbc.h,v 1.103 2006/07/18 21:20:46 hinoue Exp $
  *
  */
 
@@ -17,6 +17,7 @@
 #ifndef WIN32
 #include "config.h"
 #else
+#define    WIN32_LEAN_AND_MEAN
 #include <windows.h>
 #endif
 
 #endif
 #include "version.h"
 
+#ifdef _DEBUG
+#ifdef _MEMORY_DEBUG_
+#define _CRTDBG_MAP_ALLOC
+#include <crtdbg.h>
+#endif /* _MEMORY_DEBUG_ */
+#endif /* _DEBUG */
+
 #ifdef WIN32
 #include <delayimp.h>
 #endif /* WIN32 */
index 1c53ed179136dedf46f012c1cf9c738b1298fb0b..d5fe5be69989cb69e7ff234f5f4ff323fe48c6a9 100644 (file)
@@ -92,6 +92,7 @@
 #define DS_TRANSACTION_ROLLBACK        1081
 #define DS_STATEMENT_ROLLBACK      1082
 #define DRV_DTCLOG         1083
+#define DS_EXTRA_OPTIONS       1084
 
 // Next default values for new objects
 // 
 #ifndef APSTUDIO_READONLY_SYMBOLS
 #define _APS_NEXT_RESOURCE_VALUE        105
 #define _APS_NEXT_COMMAND_VALUE         40001
-#define _APS_NEXT_CONTROL_VALUE         1084
+#define _APS_NEXT_CONTROL_VALUE         1085
 #define _APS_NEXT_SYMED_VALUE           101
 #endif
 #endif
index fdff099fa48933ecee9433177137dc5f309f0fdf..71825dba39c9452fce7a84521b3a12fc5eb4b6ce 100644 (file)
--- a/results.c
+++ b/results.c
@@ -112,7 +112,7 @@ static BOOL SC_pre_execute_ok(StatementClass *stmt, BOOL build_fi, int col_idx,
 
 inolog("build_fi=%d reloid=%u\n", build_fi, reloid);
        if (build_fi && 0 != QR_get_attid(result, col_idx))
-           getCOLIfromTI(func, stmt, reloid, &ti);
+           getCOLIfromTI(func, NULL, stmt, reloid, &ti);
 inolog("nfields=%d\n", irdflds->nfields);
        if (irdflds->fi && col_idx < (int) irdflds->nfields)
        {
@@ -732,7 +732,7 @@ inolog("COLUMN_SCALE=%d\n", value);
            break;
 
        case SQL_COLUMN_TYPE_NAME: /* == SQL_DESC_TYPE_NAME */
-           p = pgtype_to_name(stmt, field_type);
+           p = pgtype_to_name(stmt, field_type, fi && fi->auto_increment);
            break;
 
        case SQL_COLUMN_UNSIGNED: /* == SQL_DESC_UNSINGED */
@@ -758,6 +758,8 @@ inolog("COLUMN_SCALE=%d\n", value);
                    stricmp(name, "ctid") == 0 ||
                    stricmp(name, "xmin") == 0)
                    value = SQL_ATTR_READONLY;
+               else if (conn->ms_jet && fi && fi->auto_increment)
+                   value = SQL_ATTR_READONLY;
            }
 
            mylog("%s: UPDATEABLE = %d\n", func, value);
@@ -801,7 +803,7 @@ inolog("COLUMN_SCALE=%d\n", value);
                value = 0;
            break;
        case SQL_DESC_LOCAL_TYPE_NAME:
-           p = pgtype_to_name(stmt, field_type);
+           p = pgtype_to_name(stmt, field_type, fi && fi->auto_increment);
            break;
        case SQL_DESC_TYPE:
            value = pgtype_to_sqldesctype(stmt, field_type, col_idx);
index e11c393b2010afd2b74216d342f2f67b3dc9b5c9..d9644710bc765a8eee96aa7370cad3bc08d151cf 100644 (file)
--- a/socket.c
+++ b/socket.c
@@ -74,7 +74,6 @@ SOCK_Constructor(const ConnectionClass *conn)
            free(rv);
            return NULL;
        }
-       rv->sadr = NULL;
        rv->errormsg = NULL;
        rv->errornumber = 0;
        rv->reverse = FALSE;
@@ -118,31 +117,17 @@ SOCK_Destructor(SocketClass *self)
 
    if (self->buffer_out)
        free(self->buffer_out);
-   if (self->sadr && self->sadr != (struct sockaddr *) &(self->sadr_in))
-       free(self->sadr);
 
    free(self);
 }
 
 
 char
-SOCK_connect_to(SocketClass *self, unsigned short port, char *hostname)
+SOCK_connect_to(SocketClass *self, unsigned short port, char *hostname, long timeout)
 {
-#if defined (POSIX_MULTITHREAD_SUPPORT)
-   const int bufsz = 8192; 
-   char buf[bufsz];
-   int error = 0;
-   struct hostent host;
-   struct hostent* hp = &host;
-#else
-   struct hostent* hp;
-#endif /* POSIX_MULTITHREAD_SUPPORT */
-   struct sockaddr_in *in;
-#ifdef HAVE_UNIX_SOCKETS
-   struct sockaddr_un *un;
-#endif /* HAVE_UNIX_SOCKETS */
-   int family, sLen; 
-   unsigned long iaddr;
+   struct addrinfo rest, *addrs = NULL, *curadr = NULL;
+   int family; 
+   char    retval = 0;
 
    if (self->socket != -1)
    {
@@ -156,58 +141,33 @@ SOCK_connect_to(SocketClass *self, unsigned short port, char *hostname)
     */
    if (hostname && hostname[0])
    {
-       iaddr = inet_addr(hostname);
-       memset((char *) &(self->sadr_in), 0, sizeof(self->sadr_in));
-       in = &(self->sadr_in);
-       in->sin_family = family = AF_INET;
-       in->sin_port = htons(port);
-       sLen = sizeof(self->sadr_in);
-       if (iaddr == INADDR_NONE)
+       char    portstr[16];
+       int ret;
+
+       memset(&rest, 0, sizeof(rest));
+       rest.ai_socktype = SOCK_STREAM;
+       rest.ai_family = AF_UNSPEC;
+       snprintf(portstr, sizeof(portstr), "%d", port);
+       if (inet_addr(hostname) != INADDR_NONE)
+           rest.ai_flags = AI_NUMERICHOST; 
+       ret = getaddrinfo(hostname, portstr, &rest, &addrs);
+       if (ret || !addrs)
        {
-#if defined (POSIX_MULTITHREAD_SUPPORT) 
-  #if defined (HAVE_GETIPNODEBYNAME) /* Free-BSD ? */
-           hp = getipnodebyname(hostname, AF_INET, 0, &error); 
-  #elif defined (PGS_REENTRANT_API_1) /* solaris, irix */
-           hp = gethostbyname_r(hostname, hp, buf, bufsz, &error);
-  #elif defined (PGS_REENTRANT_API_2) /* linux */
-           int result = 0;
-           result = gethostbyname_r(hostname, hp, buf, bufsz, &hp, &error);
-           if (result)
-               hp = NULL;
-  #else
-           hp = gethostbyname(hostname);
-  #endif /* HAVE_GETIPNODEBYNAME */
-#else
-           hp = gethostbyname(hostname);
-#endif /* POSIX_MULTITHREAD_SUPPORT */
-           if (hp == NULL)
-           {
-               SOCK_set_error(self, SOCKET_HOST_NOT_FOUND, "Could not resolve hostname.");
-               return 0;
-           }
-           memcpy(&(in->sin_addr), hp->h_addr, hp->h_length);
-#if defined (HAVE_GETIPNODEBYNAME)
-           freehostent(hp);
-#endif /* HAVE_GETIPNODEBYNAME */
+           SOCK_set_error(self, SOCKET_HOST_NOT_FOUND, "Could not resolve hostname.");
+           if (addrs)
+               freeaddrinfo(addrs);
+           return 0;
        }
-       else
-           memcpy(&(in->sin_addr), (struct in_addr *) & iaddr, sizeof(iaddr));
-       self->sadr = (struct sockaddr *) in;
+       curadr = addrs;
    }
    else
 #ifdef HAVE_UNIX_SOCKETS
    {
-       un = (struct sockaddr_un *) malloc(sizeof(struct sockaddr_un));
-       if (!un)
-       {
-           SOCK_set_error(self, SOCKET_COULD_NOT_CREATE_SOCKET, "coulnd't allocate memory for un.");
-           return 0;
-       }
-       un->sun_family = family = AF_UNIX;
-       /* passing NULL means that this only suports the pg default "/tmp" */
+       struct sockaddr_un *un = (struct sockaddr_un *) &(self->sadr_area);
+       family = un->sun_family = AF_UNIX;
+       /* passing NULL means that this only supports the pg default "/tmp" */
        UNIXSOCK_PATH(un, port, ((char *) NULL));
-       sLen = UNIXSOCK_LEN(un);
-       self->sadr = (struct sockaddr *) un;
+       self->sadr_len = UNIXSOCK_LEN(un);
    }
 #else
    {
@@ -216,6 +176,9 @@ SOCK_connect_to(SocketClass *self, unsigned short port, char *hostname)
    }
 #endif /* HAVE_UNIX_SOCKETS */
 
+retry:
+   if (curadr)
+       family = curadr->ai_family;
    self->socket = socket(family, SOCK_STREAM, 0);
    if (self->socket == -1)
    {
@@ -223,9 +186,10 @@ SOCK_connect_to(SocketClass *self, unsigned short port, char *hostname)
        return 0;
    }
 #ifdef TCP_NODELAY
-   if (family == AF_INET)
+   if (family != AF_UNIX)
    {
-       int i, len;
+       int i;
+       socklen_t   len;
 
        i = 1;
        len = sizeof(i);
@@ -238,17 +202,117 @@ SOCK_connect_to(SocketClass *self, unsigned short port, char *hostname)
        }
    }
 #endif /* TCP_NODELAY */
+#ifdef WIN32
+   {
+       long    ioctlsocket_ret = 1;
 
-   self->sadr_len = sLen;
-   if (connect(self->socket, self->sadr, sLen) < 0)
+       /* Returns non-0 on failure, while fcntl() returns -1 on failure */
+       ioctlsocket(self->socket, FIONBIO, &ioctlsocket_ret);
+   }
+#else
+        fcntl(self->socket, F_SETFL, O_NONBLOCK);
+#endif
+
+   if (curadr)
    {
-       SOCK_set_error(self, SOCKET_COULD_NOT_CONNECT, "Could not connect to remote socket.");
-       closesocket(self->socket);
-       self->socket = (SOCKETFD) -1;
-       return 0;
+       struct sockaddr *in = (struct sockaddr *) &(self->sadr_area);
+       memset((char *) in, 0, sizeof(self->sadr_area));
+       memcpy(in, curadr->ai_addr, curadr->ai_addrlen);
+       self->sadr_len = curadr->ai_addrlen;
+   }
+   if (connect(self->socket, (struct sockaddr *) &(self->sadr_area), self->sadr_len) < 0)
+   {
+       int ret, optval;
+       fd_set  fds;
+       struct  timeval tm;
+       socklen_t   optlen = sizeof(optval);
+       time_t  t_now, t_finish;
+       BOOL    tm_exp = FALSE;
+
+       switch (SOCK_ERRNO)
+       {
+           case 0:
+           case EINPROGRESS:
+           case EINTR:
+           case EWOULDBLOCK:
+                   break;
+           default:
+               SOCK_set_error(self, SOCKET_COULD_NOT_CONNECT, "Could not connect to remote socket ..");
+               mylog("connect immediate connect error %d\n", SOCK_ERRNO);
+               goto cleanup;
+       }
+       if (timeout > 0)
+       {
+           t_now = time(NULL);
+           t_finish = t_now + timeout;
+           tm.tv_sec = timeout;
+           tm.tv_usec = 0;
+       }
+       do {
+           FD_ZERO(&fds);
+           FD_SET(self->socket, &fds);
+           ret = select(1, NULL, &fds, NULL, timeout > 0 ? &tm : NULL);
+           if (0 < ret)
+               break;
+           else if (0 == ret)
+               tm_exp = TRUE;
+           else if (EINTR != SOCK_ERRNO)
+               break;
+           else if (timeout > 0)
+           {
+               if (t_now = time(NULL), t_now >= t_finish)
+                   tm_exp = TRUE;
+               else
+               {
+                   tm.tv_sec = t_finish - t_now;
+                   tm.tv_usec = 0;
+               }
+           }
+       } while (!tm_exp);
+       if (tm_exp)
+       {
+           SOCK_set_error(self, SOCKET_COULD_NOT_CONNECT, "Could not connect .. timeout occured.");
+           goto cleanup;
+       }
+       else if (0 > ret)
+       {
+           SOCK_set_error(self, SOCKET_COULD_NOT_CONNECT, "Could not connect .. select error occured.");
+           mylog("select error ret=%d ERROR=%d\n", ret, SOCK_ERRNO);
+           goto cleanup;
+       }
+       if (getsockopt(self->socket, SOL_SOCKET, SO_ERROR,
+               (char *) &optval, &optlen) == -1)
+       {
+           SOCK_set_error(self, SOCKET_COULD_NOT_CONNECT, "Could not connect .. getsockopt error.");
+       }
+       else if (optval != 0)
+       {
+           SOCK_set_error(self, SOCKET_COULD_NOT_CONNECT, "Could not connect to remote server.");
+           mylog("connect getsockopt val=%d\n", optval);
+       }
+       else
+           retval = 1;
    }
+   else
+       retval = 1;
 
-   return 1;
+cleanup:
+   if (0 == retval)
+   {
+       if (self->socket >= 0)
+       {
+           closesocket(self->socket);
+           self->socket = (SOCKETFD) -1;
+       }
+       if (curadr && curadr->ai_next)
+       {
+           curadr = curadr->ai_next;
+           goto retry;
+       }
+       if (addrs)
+           freeaddrinfo(addrs);
+   }
+   return retval;
 }
 
 
index 30b8911737f951f3438496a619f713c2d43f6801..ebab3fe8ca45474278a9df106384850942801e6c 100644 (file)
--- a/socket.h
+++ b/socket.h
@@ -38,7 +38,8 @@ typedef unsigned int in_addr_t;
 #define HAVE_UNIX_SOCKETS
 #endif /* HAVE_SYS_UN_H */
 #else
-#include <winsock.h>
+#include <winsock2.h>
+#include <ws2tcpip.h>
 #include <libpq-fe.h>
 #include <openssl/ssl.h>
 #define SOCKETFD SOCKET
@@ -50,6 +51,9 @@ typedef unsigned int in_addr_t;
 #ifndef    ECONNRESET
 #define    ECONNRESET  WSAECONNRESET
 #endif /* ECONNRESET */
+#ifndef    EINPROGRESS
+#define    EINPROGRESS WSAEINPROGRESS
+#endif /* EINPROGRESS */
 #endif /* WIN32 */
 
 #define SOCKET_ALREADY_CONNECTED       1
@@ -82,9 +86,8 @@ struct SocketClass_
 
    char        *errormsg;
    int     errornumber;
-   struct sockaddr *sadr; /* Used for handling connections for cancel */
    int     sadr_len;
-   struct sockaddr_in sadr_in; /* Used for INET connections */
+   struct sockaddr_storage sadr_area; /* Used for various connections */
    /* SSL stuff */
    void        *ssl;       /* libpq ssl */
    void        *pqconn;    /* libpq PGConn */
@@ -137,7 +140,7 @@ struct SocketClass_
 /* Socket prototypes */
 SocketClass *SOCK_Constructor(const ConnectionClass *conn);
 void       SOCK_Destructor(SocketClass *self);
-char       SOCK_connect_to(SocketClass *self, unsigned short port, char *hostname);
+char       SOCK_connect_to(SocketClass *self, unsigned short port, char *hostname, long timeout);
 int        SOCK_get_id(SocketClass *self);
 void       SOCK_get_n_char(SocketClass *self, char *buffer, int len);
 void       SOCK_put_n_char(SocketClass *self, char *buffer, int len);
index 9883fd06375a8a795940583fc43fb2d0805e281f..626a099f9c6ea4882b452d16169dba196c88ccd5 100644 (file)
@@ -33,7 +33,6 @@
 
 #define PRN_NULLCHECK
 
-
 /* Map sql commands to statement types */
 static struct
 {
@@ -187,7 +186,7 @@ PGAPI_AllocStmt(HDBC hdbc,
 
    if (!CC_add_statement(conn, stmt))
    {
-       CC_set_error(conn, CONN_STMT_ALLOC_ERROR, "Maximum number of connections exceeded.", func);
+       CC_set_error(conn, CONN_STMT_ALLOC_ERROR, "Maximum number of statements exceeded.", func);
        SC_Destructor(stmt);
        *phstmt = SQL_NULL_HSTMT;
        return SQL_ERROR;
@@ -372,6 +371,7 @@ SC_Constructor(ConnectionClass *conn)
        rv->exec_end_row = -1;
        rv->exec_current_row = -1;
        rv->put_data = FALSE;
+       rv->ref_CC_error = FALSE;
 
        rv->lobj_fd = -1;
        INIT_NAME(rv->cursor_name);
@@ -931,7 +931,8 @@ SC_clear_error(StatementClass *self)
        QR_set_notice(res, NULL);
        res->sqlstate[0] = '\0';
    }
-   CC_clear_error(SC_get_conn(self));
+   self->stmt_time = 0;
+   SC_unref_CC_error(self);
 }
 
 
@@ -1053,6 +1054,8 @@ SC_create_errorinfo(const StatementClass *self)
        ermsg = msg;
        detailmsg = TRUE;
    }
+   if (!self->ref_CC_error)
+       msgend = TRUE;
 
    if (conn && !msgend)
    {
@@ -1290,7 +1293,7 @@ SC_get_time(StatementClass *stmt)
 {
    if (!stmt)
        return time(NULL);
-   if (!stmt->stmt_time)
+   if (0 == stmt->stmt_time)
        stmt->stmt_time = time(NULL);
    return stmt->stmt_time;
 }
@@ -2327,7 +2330,7 @@ SendExecuteRequest(StatementClass *stmt, const char *plan_name, UInt4 count)
    SOCK_put_char(sock, 'E');
    if (SOCK_get_errcode(sock) != 0)
    {
-       CC_set_error(conn, CONNECTION_COULD_NOT_SEND, "Could not send D Request to backend", func);
+       CC_set_error(conn, CONNECTION_COULD_NOT_SEND, "Could not send E Request to backend", func);
        CC_on_abort(conn, CONN_DEAD);
        return FALSE;
    }
@@ -2337,6 +2340,22 @@ SendExecuteRequest(StatementClass *stmt, const char *plan_name, UInt4 count)
 inolog("execute leng=%d\n", leng);
    SOCK_put_string(sock, plan_name);
    SOCK_put_int(sock, count, 4);
+   if (0 == count) /* Close message */
+   {
+       SOCK_put_char(sock, 'C');
+       if (SOCK_get_errcode(sock) != 0)
+       {
+           CC_set_error(conn, CONNECTION_COULD_NOT_SEND, "Could not send C Request to backend", func);
+           CC_on_abort(conn, CONN_DEAD);
+           return FALSE;
+       }
+
+       leng = 1 + strlen(plan_name) + 1;
+       SOCK_put_int(sock, leng + 4, 4); /* Close portal */
+inolog("Close leng=%d\n", leng);
+       SOCK_put_char(sock, 'P');
+       SOCK_put_string(sock, plan_name);
+   }
 
    return TRUE;
 }
index f30b9a25adcbd4516e4209b1074b4b21ae8b508f..74d85bfebeace26a2e03d3b90e114c44be4055c9 100644 (file)
@@ -213,7 +213,6 @@ struct StatementClass_
    char        parse_status;
    char        proc_return;
    Int2        statement_type; /* According to the defines above */
-   int     data_at_exec;   /* Number of params needing SQLPutData */
    int     current_exec_param;     /* The current parameter for
                             * SQLPutData */
    PutDataInfo pdata_info;
@@ -231,9 +230,11 @@ struct StatementClass_
    char        rbonerr;     /* rollback on error */
    char        discard_output_params;   /* discard output parameters on parse stage */
    char        cancel_info;     /* cancel information */
+   char        ref_CC_error;   /* refer to CC_error ? */
    pgNAME      cursor_name;
    char        *plan_name;
    Int2        num_params;
+   Int2        data_at_exec; /* Number of params needing SQLPutData */
 
    char        *stmt_with_params;  /* statement after parameter
                             * substitution */
@@ -386,6 +387,8 @@ enum
 #define SC_accessed_db(a)  ((a->rbonerr & (1L << 3)) != 0)
 #define SC_start_rbpoint(a)    (a->rbonerr |= (1L << 4))
 #define SC_started_rbpoint(a)  ((a->rbonerr & (1L << 4)) != 0)
+#define SC_unref_CC_error(a)   ((a->ref_CC_error) = FALSE)
+#define SC_ref_CC_error(a) ((a->ref_CC_error) = TRUE)
 
 
 /* For Multi-thread */
index 1709db87c6447bafd8bf1e8872c168cdc3a582f7..2385340956b822c7e8d0425cba6e925144317353 100644 (file)
--- a/version.h
+++ b/version.h
@@ -9,8 +9,8 @@
 #ifndef __VERSION_H__
 #define __VERSION_H__
 
-#define POSTGRESDRIVERVERSION      "08.02.0005"
-#define POSTGRES_RESOURCE_VERSION  "08.02.0005\0"
-#define PG_DRVFILE_VERSION     8,2,0,05
+#define POSTGRESDRIVERVERSION      "08.02.0006"
+#define POSTGRES_RESOURCE_VERSION  "08.02.0006\0"
+#define PG_DRVFILE_VERSION     8,2,0,06
 
 #endif