Skip to content

Commit be79fbf

Browse files
author
clach04
committed
Fixes Trac ticket #445 Python DBI driver crash under Windows when fetching rows from cursor on closed connection.
After an ODBC connection is closed the ODBC spec requires that the driver close and free all resources. The crash is actually expected! Added check for exception for to fetchall so that exceptions raised by fetchone are not lost. Added quick/simply fix to check connection status on fetch. The old approach for the original IngresDBI driver was to maintain a dict of cursors in the connection and when the connection was closed, close all the cursors. This is not present in this pure C extension. Really should return back to that technique. Checking the connection for each single fetch is a needless overhead. NOTE problem did not occur under Linux, it appears the Unix Ingres ODBC driver (CLI manager) returns errors when a cursor for a closed connection is used (or we just got lucky). git-svn-id: http://code.ingres.com/ingres/drivers/python/main@2112 45b5d43f-8932-4c86-835a-3654e5842839
1 parent d46739a commit be79fbf

File tree

3 files changed

+51
-7
lines changed

3 files changed

+51
-7
lines changed

dbi/iidbiconn.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -435,7 +435,6 @@ dbi_connect( IIDBI_DBC *pdbc)
435435
/*{
436436
** Name: dbi_connectionClose - Issue a rollback and close the connection.
437437
**
438-
Corrected driver to call with an r3 installatioCorrected driver to call with an r3 installation
439438
** Inputs:
440439
** None.
441440
**

dbi/iidbicurs.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ RETCODE BindParameters(IIDBI_STMT *pstmt, unsigned char isProc);
175175
** Name: dbi_cursorClose - Close the cursor
176176
**
177177
** Description:
178-
** Close the cursor
178+
** Close the ODBC cursor (not the DBI cursor)
179179
**
180180
** Inputs:
181181
** None.

dbi/ingresdbi.c

Lines changed: 50 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,24 @@
237237
** Trac ticket 446 error on execute with empty parm iterable
238238
** Created IIDBI_IsTrue(), which is now used to check (bind)
239239
** parameters for execute and executemany.
240+
** 20-Oct-2009 (clach04)
241+
** Trac ticket 445 crash under Windows when fetching rows from cursor
242+
** on closed connection.
243+
** Added check for exception for to fetchall so that exceptions raised
244+
** by fetchone are not lost.
245+
** Added quick/simply fix to check connection status on fetch. The old
246+
** approach for the original IngresDBI driver was to maintain a dict of
247+
** cursors in the connection and when the connection was closed, close
248+
** all the cursors. This is not present in this pure C extension.
249+
** Really should return back to that technique. Checking the connection
250+
** for each single fetch is a needless overhead.
251+
** NOTE problem did not occur under Linux, it appears the Unix Ingres
252+
** ODBC driver (CLI manager) returns errors when a cursor for a closed
253+
** connection is used. The Windows Ingres ODBC driver crashes. The
254+
** Windows crash is actually expected behavior based on the ODBC spec
255+
** calls to (for instance) fetch on a closed session will be using
256+
** invalid pointers as the driver is responsible for free'ing each
257+
** connection/cursror resource. Other Windows ODBC drivers also crash.
240258
**/
241259

242260
static PyObject *IIDBI_Warning;
@@ -4314,9 +4332,27 @@ static PyObject *IIDBI_cursorFetch(IIDBI_CURSOR *self)
43144332
PyObject *exception;
43154333
char *errMsg;
43164334
int result = FALSE;
4335+
IIDBI_CONNECTION *connection;
43174336

43184337
DBPRINTF(DBI_TRC_RET)("%p: IIDBI_cursorFetch {{{1\n", self);
43194338

4339+
connection = self->connection;
4340+
/* Py_INCREF(connection); we don't intend to use this and we have the GIL so no need to increment */
4341+
if (connection == (IIDBI_CONNECTION *)Py_None)
4342+
{
4343+
exception = IIDBI_InternalError;
4344+
errMsg = "Invalid connection object";
4345+
result = IIDBI_handleError((PyObject *)self, exception, errMsg);
4346+
goto errorExit;
4347+
}
4348+
else
4349+
{
4350+
if (connection->closed && !self->closed)
4351+
{
4352+
IIDBI_cursorClose(self); /* FIXME check return and exceptions...*/
4353+
}
4354+
}
4355+
43204356
if (self->closed)
43214357
{
43224358
exception = IIDBI_InterfaceError;
@@ -4929,6 +4965,7 @@ static PyObject *IIDBI_cursorFetchAll(IIDBI_CURSOR *self)
49294965
{
49304966
PyObject *list = NULL;
49314967
PyObject *row = NULL;
4968+
PyObject *lastexception = NULL;
49324969
int dbistat = 0;
49334970
PyObject *exception;
49344971
char *errMsg;
@@ -4956,10 +4993,18 @@ static PyObject *IIDBI_cursorFetchAll(IIDBI_CURSOR *self)
49564993

49574994
if (row == NULL)
49584995
{
4959-
DBPRINTF(DBI_TRC_STAT)("fetchall call to IIDBI_cursorFetch got null\n");
4960-
exception = IIDBI_DatabaseError;
4961-
errMsg = "Error fetching rows";
4962-
result = IIDBI_handleError((PyObject *)self, exception, errMsg);
4996+
lastexception = PyErr_Occurred();
4997+
if (lastexception == NULL)
4998+
{
4999+
if (PyErr_GivenExceptionMatches(lastexception, IIDBI_Error))
5000+
{
5001+
/* We have an unhandled (non-IngresDBI) exception */
5002+
DBPRINTF(DBI_TRC_STAT)("fetchall call to IIDBI_cursorFetch got null\n");
5003+
exception = IIDBI_DatabaseError;
5004+
errMsg = "Error fetching rows";
5005+
result = IIDBI_handleError((PyObject *)self, exception, errMsg);
5006+
}
5007+
}
49635008
goto errorExit;
49645009
}
49655010

@@ -5306,7 +5351,7 @@ static PyObject *IIDBI_connClose(IIDBI_CONNECTION *self)
53065351
** Name: IIDBI_cursorClose
53075352
**
53085353
** Description:
5309-
** Close a cursor object.
5354+
** Close a DBI cursor object.
53105355
**
53115356
** Inputs:
53125357
** self - cursor object.

0 commit comments

Comments
 (0)