1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
|
/* KInterbasDB Python Package - Implementation of Record Fetch
**
** 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 <alexan@users.sourceforge.net>
** [Maintainers (after version 2.0-0.3.1):]
** 2001-2002 [maz] Marek Isalski <kinterbasdb@maz.nu>
** 2002-2004 [dsr] David Rushby <woodsplitter@rocketmail.com>
** [Contributors:]
** 2001 [eac] Evgeny A. Cherkashin <eugeneai@icc.ru>
** 2001-2002 [janez] Janez Jere <janez.jere@void.si>
*/
/****************** "PRIVATE" DECLARATIONS:BEGIN *******************/
/* Technically, isc_info_sql_stmt_exec_procedure can also return a result set,
** but that statement type is handled in a separate clause of pyob_fetch. */
#define COULD_STATEMENT_RETURN_RESULT_SET(statement_type) \
( statement_type == isc_info_sql_stmt_select \
|| statement_type == isc_info_sql_stmt_select_for_upd \
)
/****************** "PRIVATE" DECLARATIONS:END *******************/
static PyObject *pyob_fetch( PyObject *self, PyObject *args ) {
CursorObject *cursor;
PyObject *row;
int statement_type;
if ( !PyArg_ParseTuple(args, "O!", &CursorType, &cursor ) ) {
return NULL;
}
CUR_REQUIRE_OPEN(cursor);
/* If the result set has been exhausted and the cursor hasn't executed a
** fresh statement since, return None rather than raising an error. This
** behavior is required by the Python DB API. */
if (cursor->last_fetch_status == 100) {
RETURN_PY_NONE;
}
/* 2003.01.26: The statement type is now cached by the cursor; it need not
** be recomputed every time. */
statement_type = cursor->statement_type;
/* 2003.02.17: Raise exception if a fetch is attempted before a statement
** has been executed. */
if (statement_type == NULL_STATEMENT_TYPE) {
raise_exception( ProgrammingError,
"Cannot fetch from this cursor because it has not executed a statement."
);
goto FETCH_ERROR_CLEANUP;
}
debug_printf2(
"\n[in pyob_fetch] STATEMENT TYPE: %d, # of output params: %d\n",
statement_type, cursor->out_sqlda->sqld
);
/* If the cursor's statement type is isc_info_sql_stmt_exec_procedure,
** then use pseudo-fetch (for reasons explained in the comments in
** function pyob_execute regarding the difference between isc_dsql_execute
** and isc_dsql_execute2). */
if (statement_type == isc_info_sql_stmt_exec_procedure) {
if (cursor->exec_proc_results != NULL) {
row = cursor->exec_proc_results;
debug_printf("[in pyob_execute] returning the single cached"
" EXECUTE PROCEDURE result row\n");
/* Don't need to change reference count of exec_proc_results because
** we're passing reference ownership to the caller of this function. */
cursor->exec_proc_results = NULL;
return row;
} else {
debug_printf("[in pyob_execute] returning None because cached"
" EXECUTE PROCEDURE results already used\n");
RETURN_PY_NONE;
}
} else if ( !COULD_STATEMENT_RETURN_RESULT_SET(statement_type) ) {
/* If the last executed statement couldn't possibly return a result set,
** the client programmer should not be asking for one.
** It is imperative that this situation be detected before the
** isc_dsql_fetch call below. Otherwise, isc_dsql_fetch will claim to
** have succeeded without really having done so, and will leave the
** cursor statement handle in an invalid state that causes the program
** to freeze when isc_dsql_free_st4tement is called (usually by object
** destructors or other cleanup code). */
const char *baseErrMsg = "Attempt to fetch row of results from a statement"
" that does not produce a result set. That statement was: ";
int baseErrMsg_len = strlen(baseErrMsg);
int entireErrorMessage_len = baseErrMsg_len + PyString_Size(cursor->previous_sql);
char *entireErrorMessage = (char *) kimem_main_malloc( sizeof(char) * (entireErrorMessage_len + 1) );
strncpy(entireErrorMessage, baseErrMsg, baseErrMsg_len);
strncpy(entireErrorMessage + baseErrMsg_len, PyString_AsString(cursor->previous_sql),
PyString_Size(cursor->previous_sql));
entireErrorMessage[entireErrorMessage_len] = '\0'; /* Add NULL terminator. */
raise_exception( ProgrammingError, entireErrorMessage );
kimem_main_free(entireErrorMessage);
goto FETCH_ERROR_CLEANUP;
}
ENTER_DB
cursor->last_fetch_status = isc_dsql_fetch( cursor->status_vector,
&cursor->stmt_handle,
cursor->connection->dialect,
cursor->out_sqlda
);
LEAVE_DB
/* isc_dsql_fetch return value meanings:
** 0 -> success
** 100 -> result set exhausted
** anything else -> error
*/
switch (cursor->last_fetch_status) {
case 0:
row = XSQLDA2Tuple(cursor, cursor->out_sqlda);
if (row == NULL) {
goto FETCH_ERROR_CLEANUP;
}
return row;
case 100:
RETURN_PY_NONE;
}
/* default: error */
raise_sql_exception( ProgrammingError, "fetch.isc_dsql_fetch: ",
cursor->status_vector
);
/* Deliberately fall through into FETCH_ERROR_CLEANUP. */
FETCH_ERROR_CLEANUP:
close_cursor_with_error(cursor); /* 2003.02.17c: */
return NULL;
} /* pyob_fetch */
|