[7.03.0203]
authorHiroshi Inoue <inoue@tpf.co.jp>
Mon, 10 Nov 2003 07:10:07 +0000 (07:10 +0000)
committerHiroshi Inoue <inoue@tpf.co.jp>
Mon, 10 Nov 2003 07:10:07 +0000 (07:10 +0000)
1) Add conversion from text to SQL_C_BINARY(bug report from Brad Wilson).
2) Change SQLColumns, SQLTables etc to initialize the statement handle
   properly(bug report from Yutaka Tanida).
3) Improve the handling of mutex under *nix(bug report from Steve Wampler).

connection.h
convert.c
environ.c
execute.c
info.c
psqlodbc.c
psqlodbc.h
results.c
statement.c
statement.h
version.h

index 7ad28186c5f62e2b50de4751c840d4d75e65a1e9..da0e9b4ed13655a2168a727e7f9d473b8c9ef8f6 100644 (file)
@@ -93,7 +93,7 @@ typedef enum
 #define LEAVE_CONN_CS(x)   LeaveCriticalSection(&((x)->cs))
 #define DELETE_CONN_CS(x)  DeleteCriticalSection(&((x)->cs))
 #elif defined(POSIX_MULTITHREAD_SUPPORT)
-#define INIT_CONN_CS(x)        pthread_mutex_init(&((x)->cs),0)
+#define INIT_CONN_CS(x)        pthread_mutex_init(&((x)->cs), getMutexAttr())
 #define ENTER_CONN_CS(x)   pthread_mutex_lock(&((x)->cs))
 #define LEAVE_CONN_CS(x)   pthread_mutex_unlock(&((x)->cs))
 #define DELETE_CONN_CS(x)  pthread_mutex_destroy(&((x)->cs))
index 4c25e5dba9afdc42e19e4ac352dc628496a7b09d..8e21b6b31fed715a7caf12f0b9d7c57f8209a2e6 100644 (file)
--- a/convert.c
+++ b/convert.c
@@ -1217,7 +1217,10 @@ inolog("2stime fr=%d\n", std_time.fr);
 
 #endif /* ODBCINT64 */
            case SQL_C_BINARY:
-               if (PG_TYPE_UNKNOWN == field_type)
+               if (PG_TYPE_UNKNOWN == field_type ||
+                   PG_TYPE_TEXT == field_type ||
+                   PG_TYPE_VARCHAR == field_type ||
+                   PG_TYPE_BPCHAR == field_type)
                {
                    int len = SQL_NULL_DATA;
 
@@ -1226,7 +1229,11 @@ inolog("2stime fr=%d\n", std_time.fr);
                    if (pcbValue)
                        *((SDWORD *) pcbValueBindRow) = len;
                    if (len > 0 && cbValueMax > 0)
+                   {
                        memcpy(rgbValueBindRow, neut_str, len < cbValueMax ? len : cbValueMax);
+                       if (cbValueMax >= len + 1)
+                           rgbValueBindRow[len] = '\0';
+                   }
                    if (cbValueMax >= len)
                        return COPY_OK;
                    else
index b9cf9d3e5e00b38bfb07072e3b483ff287bd599a..fb12a9521a617cd24351e7467325b5414da35501 100644 (file)
--- a/environ.c
+++ b/environ.c
@@ -48,7 +48,10 @@ PGAPI_AllocEnv(HENV FAR * phenv)
     * should work.
     */
    if (globals.socket_buffersize <= 0)
+   {
+       initialize_global_cs();
        getCommonDefaults(DBMS_NAME, ODBCINST_INI, NULL);
+   }
 
    *phenv = (HENV) EN_Constructor();
    if (!*phenv)
index 87777c4e44dae0082c2212dc235646116b9ab8b7..f24d1ba84c1e0d4f9e947ba994606aab36776079 100644 (file)
--- a/execute.c
+++ b/execute.c
@@ -139,13 +139,8 @@ PGAPI_ExecDirect(
 
    mylog("%s: entering...\n", func);
 
-   if (!stmt)
-   {
-       SC_log_error(func, "", NULL);
-       return SQL_INVALID_HANDLE;
-   }
-
-   SC_initialize_stmts(stmt, TRUE);
+   if (result = SC_initialize_ifclosed(stmt, func), SQL_SUCCESS != result)
+       return result;
 
    /*
     * keep a copy of the un-parametrized statement, in case they try to
@@ -161,9 +156,6 @@ PGAPI_ExecDirect(
 
    mylog("**** %s: hstmt=%u, statement='%s'\n", func, hstmt, stmt->statement);
 
-   stmt->prepare = FALSE;
-   SC_set_prepared(stmt, FALSE);
-
    /*
     * If an SQLPrepare was performed prior to this, but was left in the
     * premature state because an error occurred prior to SQLExecute then
diff --git a/info.c b/info.c
index 2164ad051426bed994512fa9154cd86ede61217a..16f23eda7bc20d1e374a4de79746aa9187e81cf0 100644 (file)
--- a/info.c
+++ b/info.c
@@ -797,14 +797,12 @@ PGAPI_GetTypeInfo(
    /* Int4 type; */
    Int4        pgType;
    Int2        sqlType;
+   RETCODE     result;
 
    mylog("%s: entering...fSqlType = %d\n", func, fSqlType);
 
-   if (!stmt)
-   {
-       SC_log_error(func, "", NULL);
-       return SQL_INVALID_HANDLE;
-   }
+   if (result = SC_initialize_ifclosed(stmt, func), SQL_SUCCESS != result)
+       return result;
 
    stmt->manual_result = TRUE;
    if (res = QR_Constructor(), !res)
@@ -1322,11 +1320,8 @@ PGAPI_Tables(
 
    mylog("%s: entering...stmt=%u scnm=%x len=%d\n", func, stmt, szTableOwner, cbTableOwner);
 
-   if (!stmt)
-   {
-       SC_log_error(func, "", NULL);
-       return SQL_INVALID_HANDLE;
-   }
+   if (result = SC_initialize_ifclosed(stmt, func), SQL_SUCCESS != result)
+       return result;
 
    stmt->manual_result = TRUE;
    stmt->errormsg_created = TRUE;
@@ -1743,11 +1738,8 @@ PGAPI_Columns(
 
    mylog("%s: entering...stmt=%u scnm=%x len=%d\n", func, stmt, szTableOwner, cbTableOwner);
 
-   if (!stmt)
-   {
-       SC_log_error(func, "", NULL);
-       return SQL_INVALID_HANDLE;
-   }
+   if (result = SC_initialize_ifclosed(stmt, func), SQL_SUCCESS != result)
+       return result;
 
    stmt->manual_result = TRUE;
    stmt->errormsg_created = TRUE;
@@ -2262,11 +2254,8 @@ PGAPI_SpecialColumns(
 
    mylog("%s: entering...stmt=%u scnm=%x len=%d colType=%d\n", func, stmt, szTableOwner, cbTableOwner, fColType);
 
-   if (!stmt)
-   {
-       SC_log_error(func, "", NULL);
-       return SQL_INVALID_HANDLE;
-   }
+   if (result = SC_initialize_ifclosed(stmt, func), SQL_SUCCESS != result)
+       return result;
    conn = SC_get_conn(stmt);
    ci = &(conn->connInfo);
 #ifdef UNICODE_SUPPORT
@@ -2497,11 +2486,8 @@ PGAPI_Statistics(
 
    mylog("%s: entering...stmt=%u scnm=%x len=%d\n", func, stmt, szTableOwner, cbTableOwner);
 
-   if (!stmt)
-   {
-       SC_log_error(func, "", NULL);
-       return SQL_INVALID_HANDLE;
-   }
+   if (result = SC_initialize_ifclosed(stmt, func), SQL_SUCCESS != result)
+       return result;
 
    stmt->manual_result = TRUE;
    stmt->errormsg_created = TRUE;
@@ -2906,11 +2892,14 @@ PGAPI_ColumnPrivileges(
 {
    CSTR func = "PGAPI_ColumnPrivileges";
    StatementClass  *stmt = (StatementClass *) hstmt;
+   RETCODE result;
 
    mylog("%s: entering...\n", func);
 
    /* Neither Access or Borland care about this. */
 
+   if (result = SC_initialize_ifclosed(stmt, func), SQL_SUCCESS != result)
+       return result;
    SC_set_error(stmt, STMT_NOT_IMPLEMENTED_ERROR, "not implemented");
    SC_log_error(func, "Function not implemented", stmt);
    return SQL_ERROR;
@@ -2953,11 +2942,8 @@ PGAPI_PrimaryKeys(
 
    mylog("%s: entering...stmt=%u scnm=%x len=%d\n", func, stmt, szTableOwner, cbTableOwner);
 
-   if (!stmt)
-   {
-       SC_log_error(func, "", NULL);
-       return SQL_INVALID_HANDLE;
-   }
+   if (result = SC_initialize_ifclosed(stmt, func), SQL_SUCCESS != result)
+       return result;
    stmt->manual_result = TRUE;
    stmt->errormsg_created = TRUE;
 
@@ -3460,11 +3446,8 @@ char     schema_fetched[SCHEMA_NAME_STORAGE_LEN + 1];
 
    mylog("%s: entering...stmt=%u\n", func, stmt);
 
-   if (!stmt)
-   {
-       SC_log_error(func, "", NULL);
-       return SQL_INVALID_HANDLE;
-   }
+   if (result = SC_initialize_ifclosed(stmt, func), SQL_SUCCESS != result)
+       return result;
 
    stmt->manual_result = TRUE;
    stmt->errormsg_created = TRUE;
@@ -4274,6 +4257,7 @@ PGAPI_ProcedureColumns(
    char        *schema_name, *procname, *params;
    QResultClass *res, *tres;
    Int4        tcount, paramcount, i, j, pgtype;
+   RETCODE     result;
    const char *likeeq = "like";
 
    mylog("%s: entering...\n", func);
@@ -4284,8 +4268,8 @@ PGAPI_ProcedureColumns(
        SC_log_error(func, "Function not implemented", stmt);
        return SQL_ERROR;
    }
-   if (!SC_recycle_statement(stmt))
-       return SQL_ERROR;
+   if (result = SC_initialize_ifclosed(stmt, func), SQL_SUCCESS != result)
+       return result;
    if (conn->schema_support)
    {
        strcpy(proc_query, "select proname, proretset, prorettype, "
@@ -4459,6 +4443,7 @@ PGAPI_Procedures(
    ConnectionClass *conn = SC_get_conn(stmt);
    char        proc_query[INFO_INQUIRY_LEN];
    QResultClass *res;
+   RETCODE     result;
    const char *likeeq = "like";
 
    mylog("%s: entering... scnm=%x len=%d\n", func, szProcOwner, cbProcOwner);
@@ -4469,8 +4454,8 @@ PGAPI_Procedures(
        SC_log_error(func, "Function not implemented", stmt);
        return SQL_ERROR;
    }
-   if (!SC_recycle_statement(stmt))
-       return SQL_ERROR;
+   if (result = SC_initialize_ifclosed(stmt, func), SQL_SUCCESS != result)
+       return result;
 
    /*
     * The following seems the simplest implementation
@@ -4588,11 +4573,12 @@ PGAPI_TablePrivileges(
    BOOL        grpauth, sys, su;
    char        (*useracl)[ACLMAX], *acl, *user, *delim, *auth;
    char        *reln, *owner, *priv, *schnm = NULL;
+   RETCODE     result;
    const char *likeeq = "like";
 
    mylog("%s: entering... scnm=%x len-%d\n", func, szTableOwner, cbTableOwner);
-   if (!SC_recycle_statement(stmt))
-       return SQL_ERROR;
+   if (result = SC_initialize_ifclosed(stmt, func), SQL_SUCCESS != result)
+       return result;
 
    /*
     * a statement is actually executed, so we'll have to do this
index 59bdd4991e054894b4c3511d94e000ca87590a46..67acb213d686c0a15e530867da6f748beb390a41 100644 (file)
@@ -25,14 +25,54 @@ GLOBAL_VALUES globals;
 
 RETCODE SQL_API SQLDummyOrdinal(void);
 
-#ifdef WIN32
-HINSTANCE NEAR s_hModule;      /* Saved module handle. */
 #if defined(WIN_MULTITHREAD_SUPPORT)
 extern CRITICAL_SECTION    qlog_cs, mylog_cs, conns_cs;
 #elif defined(POSIX_MULTITHREAD_SUPPORT)
 extern pthread_mutex_t     qlog_cs, mylog_cs, conns_cs;
+static pthread_mutexattr_t recur_attr;
+const pthread_mutexattr_t* getMutexAttr(void)
+{
+   static int  init = 1;
+
+   if (init)
+   {
+       if (0 != pthread_mutexattr_init(&recur_attr))
+           return NULL;
+       if (0 != pthread_mutexattr_settype(&recur_attr, PTHREAD_MUTEX_RECURSIVE_NP))
+           return NULL;
+   }
+   init = 0;
+
+   return  &recur_attr;
+}
 #endif /* WIN_MULTITHREAD_SUPPORT */
 
+int    initialize_global_cs(void)
+{
+   static  int init = 1;
+
+   if (!init)
+       return 0;
+   init = 0;
+#ifdef POSIX_MULTITHREAD_SUPPORT
+   getMutexAttr();
+#endif /* POSIX_MULTITHREAD_SUPPORT */
+   INIT_QLOG_CS;
+   INIT_MYLOG_CS;
+   INIT_CONNS_CS;
+
+   return 0;
+}
+
+static void finalize_global_cs(void)
+{
+   DELETE_CONNS_CS;
+   DELETE_QLOG_CS;
+   DELETE_MYLOG_CS;
+}
+
+#ifdef WIN32
+HINSTANCE NEAR s_hModule;      /* Saved module handle. */
 /* This is where the Driver Manager attaches to this Driver */
 BOOL       WINAPI
 DllMain(HANDLE hInst, ULONG ul_reason_for_call, LPVOID lpReserved)
@@ -59,9 +99,7 @@ DllMain(HANDLE hInst, ULONG ul_reason_for_call, LPVOID lpReserved)
                return FALSE;
            }
 
-           INIT_QLOG_CS;
-           INIT_MYLOG_CS;
-           INIT_CONNS_CS;
+           initialize_global_cs();
            getCommonDefaults(DBMS_NAME, ODBCINST_INI, NULL);
            break;
 
@@ -69,9 +107,7 @@ DllMain(HANDLE hInst, ULONG ul_reason_for_call, LPVOID lpReserved)
            break;
 
        case DLL_PROCESS_DETACH:
-           DELETE_CONNS_CS;
-           DELETE_QLOG_CS;
-           DELETE_MYLOG_CS;
+           finalize_global_cs();
            WSACleanup();
            return TRUE;
 
@@ -104,6 +140,7 @@ static BOOL
 __attribute__((constructor))
 init(void)
 {
+   initialize_global_cs();
    getCommonDefaults(DBMS_NAME, ODBCINST_INI, NULL);
    return TRUE;
 }
@@ -117,6 +154,7 @@ init(void)
 BOOL
 _init(void)
 {
+   initialize_global_cs();
    getCommonDefaults(DBMS_NAME, ODBCINST_INI, NULL);
    return TRUE;
 }
@@ -124,6 +162,7 @@ _init(void)
 BOOL
 _fini(void)
 {
+   finalize_global_cs();
    return TRUE;
 }
 #endif   /* not __GNUC__ */
index 616d5e54e759c937d67aeb97a92745869893a4b7..1538625ad00160691320413053b9b1c7a138b354 100644 (file)
@@ -5,7 +5,7 @@
  *
  * Comments:       See "notice.txt" for copyright and license information.
  *
- * $Id: psqlodbc.h,v 1.79 2003/10/25 04:19:22 hinoue Exp $
+ * $Id: psqlodbc.h,v 1.80 2003/11/10 07:10:07 hinoue Exp $
  *
  */
 
@@ -308,17 +308,22 @@ void      logs_on_off(int cnopen, int, int);
 
 #include "misc.h"
 
+int    initialize_global_cs(void);
+#ifdef POSIX_MULTITHTREAD_SUPPORT
+const pthread_mutexattr_t *getMutexAttr(void);
+#endif /* POSIX_MULTITHTREAD_SUPPORT */
 #ifdef UNICODE_SUPPORT
 UInt4  ucs2strlen(const SQLWCHAR *ucs2str);
 char   *ucs2_to_utf8(const SQLWCHAR *ucs2str, Int4 ilen, UInt4 *olen, BOOL tolower);
 UInt4  utf8_to_ucs2_lf(const char * utf8str, Int4 ilen, BOOL lfconv, SQLWCHAR *ucs2str, UInt4 buflen);
 #define    utf8_to_ucs2(utf8str, ilen, ucs2str, buflen) utf8_to_ucs2_lf(utf8str, ilen, FALSE, ucs2str, buflen)
 #endif /* UNICODE_SUPPORT */
+
 /*#define  _MEMORY_DEBUG_ */
 #ifdef _MEMORY_DEBUG_
-void      *debug_alloc(size_t);
-void      *debug_realloc(void *, size_t);
-char      *debug_strdup(const char *);
+void       *debug_alloc(size_t);
+void       *debug_realloc(void *, size_t);
+char       *debug_strdup(const char *);
 void       debug_free(void *);
 void       debug_memory_check(void);
 
index 182308de2a09a4a3a8e47ef8b6090d70a10271e9..2f75e68d7fa9d75bf9d0677df895b84bf308c003 100644 (file)
--- a/results.c
+++ b/results.c
@@ -115,7 +115,7 @@ PGAPI_NumResultCols(
    SC_clear_error(stmt);
 
    parse_ok = FALSE;
-   if (ci->drivers.parse && stmt->statement_type == STMT_TYPE_SELECT)
+   if (!stmt->manual_result && ci->drivers.parse && stmt->statement_type == STMT_TYPE_SELECT)
    {
        if (stmt->parse_status == STMT_PARSE_NONE)
        {
@@ -227,7 +227,7 @@ PGAPI_DescribeCol(
    icol--;                     /* use zero based column numbers */
 
    parse_ok = FALSE;
-   if (ci->drivers.parse && stmt->statement_type == STMT_TYPE_SELECT)
+   if (!stmt->manual_result && ci->drivers.parse && stmt->statement_type == STMT_TYPE_SELECT)
    {
        if (stmt->parse_status == STMT_PARSE_NONE)
        {
@@ -451,7 +451,7 @@ PGAPI_ColAttributes(
        unknown_sizes = UNKNOWNS_AS_MAX;
 
    parse_ok = FALSE;
-   if (ci->drivers.parse && stmt->statement_type == STMT_TYPE_SELECT)
+   if (!stmt->manual_result && ci->drivers.parse && stmt->statement_type == STMT_TYPE_SELECT)
    {
        if (stmt->parse_status == STMT_PARSE_NONE)
        {
index 522345eec5d41611a90df5ec2f23082e077e2921..0d16cd4c35a7cfbf0d88a5768090a4aa645dd4a8 100644 (file)
@@ -344,10 +344,10 @@ SC_Destructor(StatementClass *self)
    }
 
    /* Free the parsed field information */
-   DC_Destructor(SC_get_ARDi(self));
-   DC_Destructor(SC_get_APDi(self));
-   DC_Destructor(SC_get_IRDi(self));
-   DC_Destructor(SC_get_IPDi(self));
+   DC_Destructor((DescriptorClass *) SC_get_ARDi(self));
+   DC_Destructor((DescriptorClass *) SC_get_APDi(self));
+   DC_Destructor((DescriptorClass *) SC_get_IRDi(self));
+   DC_Destructor((DescriptorClass *) SC_get_IPDi(self));
    
    if (self->__error_message)
        free(self->__error_message);
@@ -444,7 +444,9 @@ SC_initialize_stmts(StatementClass *self, BOOL initializeOriginal)
            free(self->execute_statement);
            self->execute_statement = NULL;
        }
+       self->prepare = FALSE;
        SC_set_prepared(self,FALSE);
+       self->statement_type = STMT_TYPE_UNKNOWN;
    }
    if (self->stmt_with_params)
    {
@@ -460,6 +462,45 @@ SC_initialize_stmts(StatementClass *self, BOOL initializeOriginal)
    return 0;
 }
 
+BOOL   SC_is_open(const StatementClass *self)
+{
+   QResultClass    *res;
+
+   if (res = SC_get_Curres(self), NULL != res)
+   {
+       if (res->backend_tuples)
+           return TRUE;
+   }
+
+   return  FALSE;
+}
+
+RETCODE
+SC_initialize_ifclosed(StatementClass *self, const char *func)
+{
+   if (!self)
+   {
+       SC_log_error(func, "", NULL);
+       return SQL_INVALID_HANDLE;
+   }
+   if (self->status == STMT_EXECUTING)
+   {
+       SC_set_error(self, STMT_SEQUENCE_ERROR, "Statement is currently executing a transaction.");
+       return FALSE;
+   }
+   if (SC_is_open(self))
+   {
+       SC_set_error(self, STMT_INVALID_CURSOR_STATE_ERROR, "The cursor is open");
+       SC_log_error(func, "", self);
+       return SQL_ERROR;
+   }
+   SC_initialize_stmts(self, TRUE);
+   if (!SC_recycle_statement(self))
+       return SQL_ERROR;
+
+   return SQL_SUCCESS;
+}
+
 /*
  * Called from SQLPrepare if STMT_PREMATURE, or
  * from SQLExecute if STMT_FINISHED, or
@@ -525,7 +566,7 @@ SC_recycle_statement(StatementClass *self)
        self->ntab = 0;
    }
    /* Free the parsed field information */
-   DC_Destructor(SC_get_IRD(self));
+   DC_Destructor((DescriptorClass *) SC_get_IRD(self));
 
    self->parse_status = STMT_PARSE_NONE;
    self->updatable = FALSE;
index ae22bffc2a02a81956e965a96711a7d4789aaa0e..35da097cd96a738ffa7c60d98c69e4b2ae48508f 100644 (file)
@@ -299,6 +299,8 @@ struct StatementClass_
 StatementClass *SC_Constructor(void);
 void       InitializeStatementOptions(StatementOptions *opt);
 char       SC_Destructor(StatementClass *self);
+BOOL       SC_is_open(const StatementClass *self);
+RETCODE        SC_initialize_ifclosed(StatementClass *self, const char *func);
 int        statement_type(const char *statement);
 char       parse_statement(StatementClass *stmt);
 void       SC_pre_execute(StatementClass *self);
index 24ad8962b210b63e0ff237aef86073923d950a6b..8abd2f9b32a701eac83ebee2d2a62c159024aba9 100644 (file)
--- a/version.h
+++ b/version.h
@@ -9,8 +9,8 @@
 #ifndef __VERSION_H__
 #define __VERSION_H__
 
-#define POSTGRESDRIVERVERSION      "07.03.0202"
-#define POSTGRES_RESOURCE_VERSION  "07.03.0202\0"
-#define PG_DRVFILE_VERSION     7,3,2,02
+#define POSTGRESDRIVERVERSION      "07.03.0203"
+#define POSTGRES_RESOURCE_VERSION  "07.03.0203\0"
+#define PG_DRVFILE_VERSION     7,3,2,03
 
 #endif