I suspect that you are not the person to send this to, but I wasn't sure
authorBruce Momjian <bruce@momjian.us>
Mon, 14 Feb 2000 12:33:19 +0000 (12:33 +0000)
committerBruce Momjian <bruce@momjian.us>
Mon, 14 Feb 2000 12:33:19 +0000 (12:33 +0000)
where else to mail it. I am the maintainer of unixODBC, and we have a
set of code in our project that started life as the Postgres windows
ODBC driver, which has been ported back to unix. Anyway I have just
fixed a memory leak in the driver, and I cant see any mention of the fix
being done in the main Postgres code, so I thougth I would let you know.

Its in the statement.c module, after the COMMIT statement has been
executed in SC_Execute, the code was

Nick Gorham

src/interfaces/odbc/statement.c

index da716001299174bef5c2e9950926e6751f636409..a0791902e7df399662e1a7414c5f80afa87a5f92 100644 (file)
@@ -62,7 +62,7 @@ static struct {
 
 
 RETCODE SQL_API SQLAllocStmt(HDBC      hdbc,
-                             HSTMT FAR *phstmt)
+                HSTMT FAR *phstmt)
 {
 static char *func="SQLAllocStmt";
 ConnectionClass *conn = (ConnectionClass *) hdbc;
@@ -88,12 +88,12 @@ StatementClass *stmt;
    }
 
     if ( ! CC_add_statement(conn, stmt)) {
-        conn->errormsg = "Maximum number of connections exceeded.";
-        conn->errornumber = CONN_STMT_ALLOC_ERROR;
+   conn->errormsg = "Maximum number of connections exceeded.";
+   conn->errornumber = CONN_STMT_ALLOC_ERROR;
        CC_log_error(func, "", conn);
-        SC_Destructor(stmt);
+   SC_Destructor(stmt);
        *phstmt = SQL_NULL_HSTMT;
-        return SQL_ERROR;
+   return SQL_ERROR;
     }
 
    *phstmt = (HSTMT) stmt;
@@ -111,7 +111,7 @@ StatementClass *stmt;
 
 
 RETCODE SQL_API SQLFreeStmt(HSTMT     hstmt,
-                            UWORD     fOption)
+               UWORD     fOption)
 {
 static char *func="SQLFreeStmt";
 StatementClass *stmt = (StatementClass *) hstmt;
@@ -151,22 +151,22 @@ StatementClass *stmt = (StatementClass *) hstmt;
     } else if (fOption == SQL_CLOSE) {
        /* this should discard all the results, but leave the statement */
        /* itself in place (it can be executed again) */
-        if (!SC_recycle_statement(stmt)) {
+   if (!SC_recycle_statement(stmt)) {
            //  errormsg passed in above
            SC_log_error(func, "", stmt);
-            return SQL_ERROR;
+       return SQL_ERROR;
        }
 
     } else if(fOption == SQL_RESET_PARAMS) {
        SC_free_params(stmt, STMT_FREE_PARAMS_ALL);
 
     } else {
-        stmt->errormsg = "Invalid option passed to SQLFreeStmt.";
-        stmt->errornumber = STMT_OPTION_OUT_OF_RANGE_ERROR;
+   stmt->errormsg = "Invalid option passed to SQLFreeStmt.";
+   stmt->errornumber = STMT_OPTION_OUT_OF_RANGE_ERROR;
        SC_log_error(func, "", stmt);
-        return SQL_ERROR;
+   return SQL_ERROR;
     }
-    
+
     return SQL_SUCCESS;
 }
 
@@ -306,7 +306,7 @@ SC_Destructor(StatementClass *self)
    return TRUE;
 }
 
-/* Free parameters and free the memory from the 
+/* Free parameters and free the memory from the
    data-at-execution parameters that was allocated in SQLPutData.
 */
 void
@@ -348,7 +348,7 @@ int i;
 }
 
 
-int 
+int
 statement_type(char *statement)
 {
 int i;
@@ -365,14 +365,14 @@ int i;
    from SQLExecute if STMT_FINISHED, or
    from SQLFreeStmt(SQL_CLOSE)
  */
-char 
+char
 SC_recycle_statement(StatementClass *self)
 {
 ConnectionClass *conn;
 
 mylog("recycle statement: self= %u\n", self);
 
-   /*  This would not happen */    
+   /*  This would not happen */
    if (self->status == STMT_EXECUTING) {
        self->errornumber = STMT_SEQUENCE_ERROR;
        self->errormsg = "Statement is currently executing a transaction.";
@@ -396,7 +396,7 @@ mylog("recycle statement: self= %u\n", self);
            If so, we have to rollback that transaction.
        */
        conn = SC_get_conn(self);
-       if ( ! CC_is_in_autocommit(conn) && CC_is_in_trans(conn)) {             
+       if ( ! CC_is_in_autocommit(conn) && CC_is_in_trans(conn)) {
 
            CC_send_query(conn, "ABORT", NULL);
            CC_set_no_trans(conn);
@@ -470,7 +470,7 @@ mylog("recycle statement: self= %u\n", self);
 }
 
 /* Pre-execute a statement (SQLPrepare/SQLDescribeCol) */
-void 
+void
 SC_pre_execute(StatementClass *self)
 {
 
@@ -485,11 +485,11 @@ SC_pre_execute(StatementClass *self)
            mylog("              preprocess: after status = FINISHED, so set PREMATURE\n");
            self->status = STMT_PREMATURE;
        }
-   }  
+   }
 }
 
 /* This is only called from SQLFreeStmt(SQL_UNBIND) */
-char 
+char
 SC_unbind_cols(StatementClass *self)
 {
 Int2 lf;
@@ -508,7 +508,7 @@ Int2 lf;
     return 1;
 }
 
-void 
+void
 SC_clear_error(StatementClass *self)
 {
    self->errornumber = 0;
@@ -552,7 +552,7 @@ static char msg[4096];
    return msg;
 }
 
-char 
+char
 SC_get_error(StatementClass *self, int *number, char **message)
 {
 char rv;
@@ -576,13 +576,13 @@ char rv;
 }
 
 /* Currently, the driver offers very simple bookmark support -- it is
-   just the current row number.  But it could be more sophisticated 
+   just the current row number.  But it could be more sophisticated
    someday, such as mapping a key to a 32 bit value
 */
 unsigned long
 SC_get_bookmark(StatementClass *self)
 {
-   return (self->currTuple + 1);   
+   return (self->currTuple + 1);
 }
 
 RETCODE
@@ -601,19 +601,19 @@ ColumnInfoClass *ci;
    ci = QR_get_fields(res);        /* the column info */
 
    mylog("manual_result = %d, use_declarefetch = %d\n", self->manual_result, globals.use_declarefetch);
+
    if ( self->manual_result || ! globals.use_declarefetch) {
 
-       if (self->currTuple >= QR_get_num_tuples(res) -1 || 
+       if (self->currTuple >= QR_get_num_tuples(res) -1 ||
            (self->options.maxRows > 0 && self->currTuple == self->options.maxRows - 1)) {
 
-           /*  if at the end of the tuples, return "no data found" 
-               and set the cursor past the end of the result set 
+           /*  if at the end of the tuples, return "no data found"
+               and set the cursor past the end of the result set
            */
-           self->currTuple = QR_get_num_tuples(res);   
+           self->currTuple = QR_get_num_tuples(res);
            return SQL_NO_DATA_FOUND;
        }
+
        mylog("**** SQLFetch: manual_result\n");
        (self->currTuple)++;
    }
@@ -643,7 +643,7 @@ ColumnInfoClass *ci;
    self->last_fetch_count = 1;
 
    /*  If the bookmark column was bound then return a bookmark.
-       Since this is used with SQLExtendedFetch, and the rowset size 
+       Since this is used with SQLExtendedFetch, and the rowset size
        may be greater than 1, and an application can use row or column wise
        binding, use the code in copy_and_convert_field() to handle that.
    */
@@ -651,7 +651,7 @@ ColumnInfoClass *ci;
        char buf[32];
 
        sprintf(buf, "%ld", SC_get_bookmark(self));
-       result = copy_and_convert_field(self, 0, buf, 
+       result = copy_and_convert_field(self, 0, buf,
                                SQL_C_ULONG, self->bookmark.buffer, 0, self->bookmark.used);
    }
 
@@ -663,9 +663,9 @@ ColumnInfoClass *ci;
        self->bindings[lf].data_left = -1;
 
        if (self->bindings[lf].buffer != NULL) {
-            // this column has a binding
+       // this column has a binding
 
-            // type = QR_get_field_type(res, lf);
+       // type = QR_get_field_type(res, lf);
            type = CI_get_oid(ci, lf);      /* speed things up */
 
            mylog("type = %d\n", type);
@@ -759,13 +759,13 @@ QueryInfo qi;
            SC_log_error(func, "", self);
            return SQL_ERROR;
        }
-       
-       ok = QR_command_successful(res);   
-       
+
+       ok = QR_command_successful(res);
+
        mylog("SQLExecute: ok = %d, status = %d\n", ok, QR_get_status(res));
-       
+
        QR_Destructor(res);
-       
+
        if (!ok) {
            self->errormsg = "Could not begin a transaction";
            self->errornumber = STMT_EXEC_ERROR;
@@ -805,32 +805,33 @@ QueryInfo qi;
            qi.cursor = self->cursor_name;
            qi.row_size = globals.fetch_max;
 
-           /*  Most likely the rowset size will not be set by the application until 
-               after the statement is executed, so might as well use the cache size.  
-               The qr_next_tuple() function will correct for any discrepancies in 
+           /*  Most likely the rowset size will not be set by the application until
+               after the statement is executed, so might as well use the cache size.
+               The qr_next_tuple() function will correct for any discrepancies in
                sizes and adjust the cache accordingly.
            */
 
            sprintf(fetch, "fetch %d in %s", qi.row_size, self->cursor_name);
-           
+
            self->result = CC_send_query( conn, fetch, &qi);
        }
 
        mylog("     done sending the query:\n");
 
 
-       
+
    }
-   else  { // not a SELECT statement so don't use a cursor          
+   else  { // not a SELECT statement so don't use a cursor
        mylog("      it's NOT a select statement: stmt=%u\n", self);
        self->result = CC_send_query(conn, self->stmt_with_params, NULL);
-       
+
        //  If we are in autocommit, we must send the commit.
        if ( ! self->internal && CC_is_in_autocommit(conn) && STMT_UPDATE(self)) {
-           CC_send_query(conn, "COMMIT", NULL);
-           CC_set_no_trans(conn);
+       res = CC_send_query(conn, "COMMIT", NULL);
+       QR_Destructor(res);
+       CC_set_no_trans(conn);
        }
-       
+
    }
 
    conn->status = oldstatus;
@@ -841,19 +842,19 @@ QueryInfo qi;
 
        was_ok = QR_command_successful(self->result);
        was_nonfatal = QR_command_nonfatal(self->result);
-       
+
        if ( was_ok)
            self->errornumber = STMT_OK;
        else
            self->errornumber = was_nonfatal ? STMT_INFO_ONLY : STMT_ERROR_TAKEN_FROM_BACKEND;
-       
+
        self->currTuple = -1; /* set cursor before the first tuple in the list */
        self->current_col = -1;
        self->rowset_start = -1;
-       
+
        /* see if the query did return any result columns */
        numcols = QR_NumResultCols(self->result);
-       
+
        /* now allocate the array to hold the binding info */
        if (numcols > 0) {
            extend_bindings(self, numcols);
@@ -864,7 +865,7 @@ QueryInfo qi;
                return SQL_ERROR;
            }
        }
-       
+
    } else {        /* Bad Error -- The error message will be in the Connection */
 
        if (self->statement_type == STMT_TYPE_CREATE) {
@@ -927,7 +928,7 @@ SC_log_error(char *func, char *desc, StatementClass *self)
        qlog("                 message='%s', command='%s', notice='%s'\n", nullcheck(res->message), nullcheck(res->command), nullcheck(res->notice));
        qlog("                 status=%d, inTuples=%d\n", res->status, res->inTuples);
        }
-   
+
        //  Log the connection error if there is one
        CC_log_error(func, desc, self->hdbc);
    }