A patch to fix the following bugs.
authorHiroshi Inoue <inoue@tpf.co.jp>
Mon, 23 Apr 2001 01:00:49 +0000 (01:00 +0000)
committerHiroshi Inoue <inoue@tpf.co.jp>
Mon, 23 Apr 2001 01:00:49 +0000 (01:00 +0000)
1) [ODBC] Psqlodbc and Centura: here it is a patch
        posted by Matteo Cavalleli
2) [ODBC] pgsqODBC binding parameters II
        posted by Ludek Finstrle
3) Invalid Page Fault in PSQLODBC.DLL
        personal mail from Johann Zuschlag

   Hiroki Kataoka   kataoka@interwiz.koganei.tokyo.jp

src/interfaces/odbc/bind.c
src/interfaces/odbc/convert.c
src/interfaces/odbc/execute.c
src/interfaces/odbc/pgtypes.c
src/interfaces/odbc/pgtypes.h
src/interfaces/odbc/statement.c
src/interfaces/odbc/statement.h

index 5bade8b39560848e692ca3cc89e54f34529d2798..c70f78d4fb72db720da35ed30b432f87792259dc 100644 (file)
@@ -143,11 +143,16 @@ SQLBindParameter(
    }
 
    /* Data at exec macro only valid for C char/binary data */
-   if ((fSqlType == SQL_LONGVARBINARY || fSqlType == SQL_LONGVARCHAR) && pcbValue && *pcbValue <= SQL_LEN_DATA_AT_EXEC_OFFSET)
+   if (pcbValue && (*pcbValue == SQL_DATA_AT_EXEC ||
+           *pcbValue <= SQL_LEN_DATA_AT_EXEC_OFFSET))
        stmt->parameters[ipar].data_at_exec = TRUE;
    else
        stmt->parameters[ipar].data_at_exec = FALSE;
 
+   /* Clear premature result */
+   if (stmt->status == STMT_PREMATURE)
+       SC_recycle_statement(stmt);
+
    mylog("SQLBindParamater: ipar=%d, paramType=%d, fCType=%d, fSqlType=%d, cbColDef=%d, ibScale=%d, rgbValue=%d, *pcbValue = %d, data_at_exec = %d\n", ipar, fParamType, fCType, fSqlType, cbColDef, ibScale, rgbValue, pcbValue ? *pcbValue : -777, stmt->parameters[ipar].data_at_exec);
 
    return SQL_SUCCESS;
index 595235bf9b63ff7b5d178e7ac7c9d1c49bc12626..8b41fb1c17333f4f7da1b859880b27a3ad12bda9 100644 (file)
@@ -838,7 +838,20 @@ copy_statement_with_parameters(StatementClass *stmt)
        param_number++;
 
        if (param_number >= stmt->parameters_allocated)
-           break;
+       {
+           if (stmt->pre_executing)
+           {
+               strcpy(&new_statement[npos], "NULL");
+               npos += 4;
+               stmt->inaccurate_result = TRUE;
+               continue;
+           }
+           else
+           {
+               new_statement[npos++] = '?';
+               continue;
+           }
+       }
 
        /* Assign correct buffers based on data at exec param or not */
        if (stmt->parameters[param_number].data_at_exec)
@@ -866,8 +879,18 @@ copy_statement_with_parameters(StatementClass *stmt)
         */
        if (!buffer)
        {
-           new_statement[npos++] = '?';
-           continue;
+           if (stmt->pre_executing)
+           {
+               strcpy(&new_statement[npos], "NULL");
+               npos += 4;
+               stmt->inaccurate_result = TRUE;
+               continue;
+           }
+           else
+           {
+               new_statement[npos++] = '?';
+               continue;
+           }
        }
 
        param_ctype = stmt->parameters[param_number].CType;
index 5fc2661331d3875dce379c4a5da8abf7915d8c5c..9777f4324c2db4a4ac4792bcff9df96c2f8c8d63 100644 (file)
@@ -33,6 +33,7 @@
 #include "qresult.h"
 #include "convert.h"
 #include "bind.h"
+#include "pgtypes.h"
 #include "lobj.h"
 
 extern GLOBAL_VALUES globals;
@@ -222,17 +223,22 @@ SQLExecute(
     */
    if (stmt->prepare && stmt->status == STMT_PREMATURE)
    {
-       stmt->status = STMT_FINISHED;
-       if (stmt->errormsg == NULL)
-       {
-           mylog("%s: premature statement but return SQL_SUCCESS\n", func);
-           return SQL_SUCCESS;
-       }
+       if (stmt->inaccurate_result)
+           SC_recycle_statement(stmt);
        else
        {
-           SC_log_error(func, "", stmt);
-           mylog("%s: premature statement so return SQL_ERROR\n", func);
-           return SQL_ERROR;
+           stmt->status = STMT_FINISHED;
+           if (stmt->errormsg == NULL)
+           {
+               mylog("%s: premature statement but return SQL_SUCCESS\n", func);
+               return SQL_SUCCESS;
+           }
+           else
+           {
+               SC_log_error(func, "", stmt);
+               mylog("%s: premature statement so return SQL_ERROR\n", func);
+               return SQL_ERROR;
+           }
        }
    }
 
@@ -283,30 +289,36 @@ SQLExecute(
    }
 
 
-   /*
-    * The bound parameters could have possibly changed since the last
-    * execute of this statement?  Therefore check for params and re-copy.
-    */
-   stmt->data_at_exec = -1;
-   for (i = 0; i < stmt->parameters_allocated; i++)
+   /* Check if statement has any data-at-execute parameters when it is not in SC_pre_execute. */
+   if (!stmt->pre_executing)
    {
-       /* Check for data at execution parameters */
-       if (stmt->parameters[i].data_at_exec == TRUE)
+
+       /*
+        * The bound parameters could have possibly changed since the last
+        * execute of this statement?  Therefore check for params and re-copy.
+        */
+       stmt->data_at_exec = -1;
+       for (i = 0; i < stmt->parameters_allocated; i++)
        {
-           if (stmt->data_at_exec < 0)
-               stmt->data_at_exec = 1;
-           else
-               stmt->data_at_exec++;
+           /* Check for data at execution parameters */
+           if (stmt->parameters[i].data_at_exec == TRUE)
+           {
+               if (stmt->data_at_exec < 0)
+                   stmt->data_at_exec = 1;
+               else
+                   stmt->data_at_exec++;
+           }
        }
-   }
-   /* If there are some data at execution parameters, return need data */
+       /* If there are some data at execution parameters, return need data */
 
-   /*
-    * SQLParamData and SQLPutData will be used to send params and execute
-    * the statement.
-    */
-   if (stmt->data_at_exec > 0)
-       return SQL_NEED_DATA;
+       /*
+        * SQLParamData and SQLPutData will be used to send params and execute
+        * the statement.
+        */
+       if (stmt->data_at_exec > 0)
+           return SQL_NEED_DATA;
+
+   }
 
 
    mylog("%s: copying statement params: trans_status=%d, len=%d, stmt='%s'\n", func, conn->transact_status, strlen(stmt->statement), stmt->statement);
@@ -777,8 +789,7 @@ SQLPutData(
 
        }
        else
-       {                       /* for handling text fields and small
-                                * binaries */
+       {                       /* for handling fields */
 
            if (cbValue == SQL_NTS)
            {
@@ -793,16 +804,35 @@ SQLPutData(
            }
            else
            {
-               current_param->EXEC_buffer = malloc(cbValue + 1);
-               if (!current_param->EXEC_buffer)
+               Int2 ctype = current_param->CType;
+               if (ctype == SQL_C_DEFAULT)
+                   ctype = sqltype_to_default_ctype(current_param->SQLType);
+               if (ctype == SQL_C_CHAR || ctype == SQL_C_BINARY)
                {
-                   stmt->errornumber = STMT_NO_MEMORY_ERROR;
-                   stmt->errormsg = "Out of memory in SQLPutData (2)";
-                   SC_log_error(func, "", stmt);
-                   return SQL_ERROR;
+                   current_param->EXEC_buffer = malloc(cbValue + 1);
+                   if (!current_param->EXEC_buffer)
+                   {
+                       stmt->errornumber = STMT_NO_MEMORY_ERROR;
+                       stmt->errormsg = "Out of memory in SQLPutData (2)";
+                       SC_log_error(func, "", stmt);
+                       return SQL_ERROR;
+                   }
+                   memcpy(current_param->EXEC_buffer, rgbValue, cbValue);
+                   current_param->EXEC_buffer[cbValue] = '\0';
+               }
+               else
+               {
+                   Int4 used = ctype_length(ctype);
+                   current_param->EXEC_buffer = malloc(used);
+                   if (!current_param->EXEC_buffer)
+                   {
+                       stmt->errornumber = STMT_NO_MEMORY_ERROR;
+                       stmt->errormsg = "Out of memory in SQLPutData (2)";
+                       SC_log_error(func, "", stmt);
+                       return SQL_ERROR;
+                   }
+                   memcpy(current_param->EXEC_buffer, rgbValue, used);
                }
-               memcpy(current_param->EXEC_buffer, rgbValue, cbValue);
-               current_param->EXEC_buffer[cbValue] = '\0';
            }
        }
    }
index 4b5b4db74e63845ced266807378cd6a4e4fd4203..f033be5f7d75bc54554d238df29892f41d14b159 100644 (file)
@@ -955,3 +955,56 @@ sqltype_to_default_ctype(Int2 sqltype)
            return SQL_C_CHAR;
    }
 }
+
+Int4
+ctype_length(Int2 ctype)
+{
+   switch (ctype)
+   {
+       case SQL_C_SSHORT:
+       case SQL_C_SHORT:
+           return sizeof(SWORD);
+
+       case SQL_C_USHORT:
+           return sizeof(UWORD);
+
+       case SQL_C_SLONG:
+       case SQL_C_LONG:
+           return sizeof(SDWORD);
+
+       case SQL_C_ULONG:
+           return sizeof(UDWORD);
+
+       case SQL_C_FLOAT:
+           return sizeof(SFLOAT);
+
+       case SQL_C_DOUBLE:
+           return sizeof(SDOUBLE);
+
+       case SQL_C_BIT:
+           return sizeof(UCHAR);
+
+       case SQL_C_STINYINT:
+       case SQL_C_TINYINT:
+           return sizeof(SCHAR);
+
+       case SQL_C_UTINYINT:
+           return sizeof(UCHAR);
+
+       case SQL_C_DATE:
+           return sizeof(DATE_STRUCT);
+
+       case SQL_C_TIME:
+           return sizeof(TIME_STRUCT);
+
+       case SQL_C_TIMESTAMP:
+           return sizeof(TIMESTAMP_STRUCT);
+
+       case SQL_C_BINARY:
+       case SQL_C_CHAR:
+           return 0;
+
+       default:                /* should never happen */
+           return 0;
+   }
+}
index 7130bd423c9e47c3ebc8ab579d5677f2959718c6..03cc2babd16a1f2d32daafa270cac76cfe7b4793 100644 (file)
@@ -92,5 +92,6 @@ char     *pgtype_literal_suffix(StatementClass *stmt, Int4 type);
 char      *pgtype_create_params(StatementClass *stmt, Int4 type);
 
 Int2       sqltype_to_default_ctype(Int2 sqltype);
+Int4       ctype_length(Int2 ctype);
 
 #endif
index 8b7a67babd30c03b724f057a026386d91bc5142e..497364ba84d633e0714dd3f5a663684baa3116d4 100644 (file)
@@ -291,6 +291,9 @@ SC_Constructor(void)
 
        /* Clear Statement Options -- defaults will be set in AllocStmt */
        memset(&rv->options, 0, sizeof(StatementOptions));
+
+       rv->pre_executing = FALSE;
+       rv->inaccurate_result = FALSE;
    }
    return rv;
 }
@@ -518,6 +521,7 @@ SC_recycle_statement(StatementClass *self)
        QR_Destructor(self->result);
        self->result = NULL;
    }
+   self->inaccurate_result = FALSE;
 
    /****************************************************************/
    /* Reset only parameters that have anything to do with results */
@@ -550,18 +554,33 @@ SC_recycle_statement(StatementClass *self)
 void
 SC_pre_execute(StatementClass *self)
 {
-
    mylog("SC_pre_execute: status = %d\n", self->status);
 
    if (self->status == STMT_READY)
    {
        mylog("              preprocess: status = READY\n");
 
-       SQLExecute(self);
+       if (self->statement_type == STMT_TYPE_SELECT)
+       {
+           char old_pre_executing = self->pre_executing;
+           self->pre_executing = TRUE;
+           self->inaccurate_result = FALSE;
+
+           SQLExecute(self);
+
+           self->pre_executing = old_pre_executing;
 
-       if (self->status == STMT_FINISHED)
+           if (self->status == STMT_FINISHED)
+           {
+               mylog("              preprocess: after status = FINISHED, so set PREMATURE\n");
+               self->status = STMT_PREMATURE;
+           }
+       }
+       else
        {
-           mylog("              preprocess: after status = FINISHED, so set PREMATURE\n");
+           self->result = QR_Constructor();
+           QR_set_status(self->result, PGRES_TUPLES_OK);
+           self->inaccurate_result = TRUE;
            self->status = STMT_PREMATURE;
        }
    }
index 69f8274615c36ff252bffeda13b717795bf1da1f..00b39962d6ca0f401c15a80c1a340cfc417a16c8 100644 (file)
@@ -214,6 +214,9 @@ struct StatementClass_
                                                         * parameter
                                                         * substitution */
 
+   char        pre_executing;  /* This statement is prematurely executing */
+   char        inaccurate_result;      /* Current status is PREMATURE
+                                        * but result is inaccurate */
 };
 
 #define SC_get_conn(a)   (a->hdbc)