/* KInterbasDB Python Package - Implementation of Cursor ** ** Version 3.1 ** ** The following contributors hold Copyright (C) over their respective ** portions of code (see license.txt for details): ** ** [Original Author (maintained through version 2.0-0.3.1):] ** 1998-2001 [alex] Alexander Kuznetsov ** [Maintainers (after version 2.0-0.3.1):] ** 2001-2002 [maz] Marek Isalski ** 2002-2004 [dsr] David Rushby ** [Contributors:] ** 2001 [eac] Evgeny A. Cherkashin ** 2001-2002 [janez] Janez Jere */ static CursorObject *new_cursor(ConnectionObject *connection) { CursorObject *cursor; Py_INCREF(connection); /* It's important that this statement remain BEFORE ** the CursorObject instantiation, because the connection is DECREFed in ** the error handler at the bottom of this function. */ cursor = PyObject_New(CursorObject, &CursorType); if (cursor == NULL) { goto NEW_CURSOR_FAIL; } /* Nullify all of the cursor's fields first, so that if one of the field ** initializations that requires additional allocation fails, the cleanup ** code can check each field without fear of referring to uninitialized ** memory. */ cursor->connection = NULL; cursor->stmt_handle = NULL; cursor->in_sqlda = NULL; cursor->out_sqlda = NULL; cursor->name = NULL; cursor->in_var_orig_spec = NULL; cursor->out_buffer = NULL; cursor->previous_sql = NULL; cursor->statement_type = NULL_STATEMENT_TYPE; cursor->objects_to_release_after_execute = NULL; cursor->exec_proc_results = NULL; cursor->last_fetch_status = 0; /* Inherit the contents of our connection's status vector: */ memcpy(&cursor->status_vector, &connection->status_vector, sizeof(ISC_STATUS) * STATUS_VECTOR_SIZE ); cursor->_state = CURSOR_STATE_OPEN; cursor->type_trans_in = NULL; cursor->type_trans_out = NULL; cursor->output_type_trans_return_type_dict = NULL; /* Now that nullification is done, perform the non-null initializations: */ /* Already incremented connection's ref count near top of this function. */ cursor->connection = connection; if (reallocate_sqlda(&cursor->in_sqlda, TRUE) == -1) { goto NEW_CURSOR_FAIL; } if (reallocate_sqlda(&cursor->out_sqlda, FALSE) == -1) { goto NEW_CURSOR_FAIL; } cursor->objects_to_release_after_execute = PyList_New(0); if (cursor->objects_to_release_after_execute == NULL) { goto NEW_CURSOR_FAIL; } return cursor; NEW_CURSOR_FAIL: Py_DECREF(connection); Py_XDECREF(cursor); /* 2005.05.20: Call destructor only indirectly. */ return NULL; } /* new_cursor */ /* If self is not an open cursor, raises the supplied error message ** (or a default if no error message is supplied). ** Returns 0 if the cursor was open; -1 if it failed the test. */ static int _cur_require_open(CursorObject *self, char *failure_message) { if ( self != NULL ) { char *conn_failure_message = "Invalid cursor state. The connection" " associated with this cursor is not open, and therefore the cursor" " should not be open either."; if ( _conn_require_open(self->connection, conn_failure_message) != 0 ) { return -1; } else if ( self->_state == CURSOR_STATE_OPEN) { return 0; } } if (failure_message == NULL) { failure_message = "Invalid cursor state. The cursor must be" " OPEN to perform this operation."; } raise_exception(ProgrammingError, failure_message); return -1; } /* _cur_require_open */ static void free_cursor_cache(CursorObject *cursor) { Py_XDECREF(cursor->previous_sql); cursor->previous_sql = NULL; cursor->statement_type = NULL_STATEMENT_TYPE; if (cursor->in_var_orig_spec != NULL) { kimem_plain_free(cursor->in_var_orig_spec); cursor->in_var_orig_spec = NULL; } _free_cursor_exec_proc_results_cache(cursor); } /* free_cursor_cache */ static void _free_cursor_exec_proc_results_cache(CursorObject *cursor) { /* Free ONLY those cursor variables that pertain to the cache of ** EXECUTE PROCEDURE results that was introduced in answer to bug #520793. ** This function is separate from free_cursor_cache so that it can be ** called separately, when it makes sense to free the cached EXEC PROC row, ** but not to free the cursor's memory as a whole. */ if (cursor->exec_proc_results != NULL) { /* This block will only be reached if the client executed a result- ** returning stored procedure with the EXECUTE PROCEDURE statement ** (via Cursor.execute), but the client never retrieved the results ** (via Cursor.fetch*). */ Py_DECREF(cursor->exec_proc_results); cursor->exec_proc_results = NULL; } } /* _free_cursor_exec_proc_results_cache */ static void clear_cursor(CursorObject *cursor, PyObject *sql_about_to_be_executed) { /* $sql_about_to_be_executed should be the incoming SQL string if this ** function is being called from pyob_execute, NULL if this function is being ** called from anywhere else. */ /* This action might be thought of as a "retaining close". */ _free_cursor_exec_proc_results_cache(cursor); /* Quote from IB 6 API Guide p334: ** "A cursor need only be closed [with DSQL_close before DSQL_drop] if it was ** previously opened and associated with stmt_handle by ** isc_dsql_set_cursor_name(). ** DSQL_close closes a cursor, but the statement it was associated with ** remains available for further execution." ** ** Additional wrinkle: if we're reusing an old statement handle (i.e., if the ** new SQL string sent for execution is the same as the previous SQL string), ** we must ** isc_dsql_free_statement(..., ..., DSQL_close); ** the handle, but not set it NULL (which would prevent reuse). */ if (cursor->stmt_handle != NULL) { boolean new_sql_same_as_old = ( sql_about_to_be_executed != NULL && cursor->previous_sql != NULL && /* If the PyObject pointers point to the same memory location, the ** two objects are certainly equal--in fact, they're IDentical ** (id(sql_about_to_be_executed) == id(cursor->previous_sql)). If ** the pointers refer to different memory locations, the two objects ** are still equal if their contents match. */ ( sql_about_to_be_executed == cursor->previous_sql || PyObject_Compare(sql_about_to_be_executed, cursor->previous_sql) == 0 ) ); boolean cursor_name_specified = cursor->name != NULL; if (new_sql_same_as_old || cursor_name_specified) { /* The Python layer of kinterbasdb shouldn't have allowed the connection ** to close without closing its cursors first, but if that *was* allowed ** to happen, there's nothing we can do about except avoid calling the ** now-dangerous isc_dsql_free_statement. */ if (cursor->connection->_state != CONNECTION_STATE_CLOSED) { ENTER_DB isc_dsql_free_statement( cursor->status_vector, &cursor->stmt_handle, DSQL_close ); LEAVE_DB } if (!new_sql_same_as_old) { cursor->stmt_handle = NULL; } if (cursor_name_specified) { Py_DECREF(cursor->name); cursor->name = NULL; } } } /* Clear the fetch status flag because we might be about to deal with a new ** result set. In any case, we will never again fetch from the old result ** set (if any). */ cursor->last_fetch_status = 0; cursor->_state = CURSOR_STATE_CLOSED; } /* clear_cursor */ void close_cursor(CursorObject *cursor) { clear_cursor(cursor, NULL); /* Moved this operation here from delete_cursor in cursor state management ** reorganization. */ if (cursor->stmt_handle != NULL) { /* The Python layer of kinterbasdb shouldn't have allowed the connection to ** close without closing its cursors first, but if that *was* allowed to ** happen, there's nothing we can do about except avoid calling the ** now-dangerous isc_dsql_free_statement. */ if (cursor->connection->_state != CONNECTION_STATE_CLOSED) { ENTER_DB isc_dsql_free_statement( cursor->status_vector, &cursor->stmt_handle, DSQL_drop /* DSQL_drop means "free resources allocated for this statement." */ ); LEAVE_DB } cursor->stmt_handle = NULL; } if (cursor->out_buffer != NULL) { kimem_main_free(cursor->out_buffer); cursor->out_buffer = NULL; } if (cursor->name != NULL) { Py_DECREF(cursor->name); cursor->name = NULL; } free_cursor_cache(cursor); } /* close_cursor */ static void close_cursor_with_error(CursorObject *cursor) { /* Close the cursor because one of its operation resulted in an exception, ** but flag the cursor as ready to be used again. */ close_cursor(cursor); /* 2003.02.17c: No change needed. */ cursor->_state = CURSOR_STATE_OPEN; } /* close_cursor_with_error */ static void delete_cursor(CursorObject *cursor) { assert (cursor->connection != NULL); close_cursor(cursor); /* 2003.02.17c: No change needed. */ Py_DECREF(cursor->connection); cursor->connection = NULL; /* ->connection field is used as flag, so nullify it. */ if (cursor->in_sqlda != NULL) { int i; for ( i = 0; i < cursor->in_sqlda->sqln; i++ ) { XSQLVAR *sqlvar = cursor->in_sqlda->sqlvar + i; assert (sqlvar->sqlind != NULL); kimem_main_free(sqlvar->sqlind); /* The NULL indicator flag. */ sqlvar->sqlind = NULL; } kimem_xsqlda_free(cursor->in_sqlda); cursor->in_sqlda = NULL; } if (cursor->out_sqlda != NULL) { kimem_xsqlda_free(cursor->out_sqlda); cursor->out_sqlda = NULL; } Py_XDECREF(cursor->objects_to_release_after_execute); Py_XDECREF(cursor->type_trans_in); Py_XDECREF(cursor->type_trans_out); Py_XDECREF(cursor->output_type_trans_return_type_dict); } /* delete_cursor */ static void pyob_cursor_del(PyObject *cursor) { CursorObject *cursor_cast = (CursorObject *) cursor; /* Only attempt to release the cursor's fields if they've (at least begun to ** be) initialized rather than merely nullified: */ if (cursor_cast->connection != NULL) { delete_cursor(cursor_cast); } /* Release the cursor struct itself: */ PyObject_Del(cursor); } /* pyob_cursor_del */ static PyObject *pyob_cursor(PyObject *self, PyObject *args) { ConnectionObject *connection; if ( !PyArg_ParseTuple( args, "O!", &ConnectionType, &connection ) ) { return NULL; } CONN_REQUIRE_OPEN(connection); return (PyObject *) new_cursor(connection); } /* pyob_cursor */ static PyObject *pyob_close_cursor(PyObject *self, PyObject *args) { CursorObject *cursor; if ( !PyArg_ParseTuple( args, "O!", &CursorType, &cursor ) ) { return NULL; } CUR_REQUIRE_OPEN(cursor); close_cursor(cursor); /* 2003.02.17c: No change needed. */ RETURN_PY_NONE; } /* pyob_close_cusor */ static PyObject *pyob_set_cursor_name(PyObject *self, PyObject *args) { CursorObject *cursor; PyObject *name; if ( !PyArg_ParseTuple( args, "O!O!", &CursorType, &cursor, &PyString_Type, &name ) ) { return NULL; } CUR_REQUIRE_OPEN(cursor); if (cursor->stmt_handle == NULL) { raise_exception_with_numeric_error_code(ProgrammingError, -901, "This cursor has not yet executed a statement, so setting its 'name'" " would be meaningless." ); return NULL; } if (cursor->name != NULL) { /* Cannot reset the cursor's name while operating in the context of the ** same statement for which the original name was declared. */ raise_exception_with_numeric_error_code(ProgrammingError, -502, "Cannot set this cursor's name, because its name has already been" " declared in the context of the statement that the cursor is" " currently executing." ); return NULL; } /* Now make the association inside the database. */ { char *name_ptr = PyString_AsString(name); ENTER_DB isc_dsql_set_cursor_name(cursor->status_vector, &cursor->stmt_handle, name_ptr, 0 ); LEAVE_DB } if ( DB_API_ERROR(cursor->status_vector) ) { raise_sql_exception( OperationalError, "Could not set cursor name: ", cursor->status_vector ); return NULL; } /* Store the name for retrieval from the Python level. */ Py_INCREF(name); cursor->name = name; RETURN_PY_NONE; } /* pyob_set_cursor_name */ static PyObject *pyob_get_cursor_name(PyObject *self, PyObject *args) { CursorObject *cursor; if ( !PyArg_ParseTuple( args, "O!", &CursorType, &cursor ) ) { return NULL; } CUR_REQUIRE_OPEN(cursor); if (cursor->name == NULL) { RETURN_PY_NONE; } else { Py_INCREF(cursor->name); return cursor->name; } } /* pyob_get_cursor_name */ static PyObject *pyob_is_purportedly_open(PyObject *self, PyObject *args) { PyObject *incoming; if ( !PyArg_ParseTuple( args, "O", &incoming ) ) { return NULL; } if ( PyObject_TypeCheck(incoming, &ConnectionType) ) { return PyBool_FromLong( ((ConnectionObject *) incoming)->_state == CONNECTION_STATE_OPEN ); } else if ( PyObject_TypeCheck(incoming, &CursorType) ) { return PyBool_FromLong( ((CursorObject *) incoming)->_state == CURSOR_STATE_OPEN ); } else { PyErr_SetString(PyExc_TypeError, "Object must be of type ConnectionType or CursorType."); return NULL; } } /* pyob_get_cursor_name */