cpython/Modules/_sqlite/cursor.c
Thomas Wouters fc7bb8c786 Merged revisions 53304-53433,53435-53450 via svnmerge from
svn+ssh://pythondev@svn.python.org/python/trunk

........
  r53304 | vinay.sajip | 2007-01-09 15:50:28 +0100 (Tue, 09 Jan 2007) | 1 line

  Bug #1627575: Added _open() method to FileHandler which can be used to reopen files. The FileHandler instance now saves the encoding (which can be None) in an attribute called "encoding".
........
  r53305 | vinay.sajip | 2007-01-09 15:51:36 +0100 (Tue, 09 Jan 2007) | 1 line

  Added entry about addition of _open() method to logging.FileHandler.
........
  r53306 | vinay.sajip | 2007-01-09 15:54:56 +0100 (Tue, 09 Jan 2007) | 1 line

  Added a docstring
........
  r53316 | thomas.heller | 2007-01-09 20:19:33 +0100 (Tue, 09 Jan 2007) | 4 lines

  Verify the sizes of the basic ctypes data types against the struct
  module.

  Will backport to release25-maint.
........
  r53340 | gustavo.niemeyer | 2007-01-10 17:13:40 +0100 (Wed, 10 Jan 2007) | 3 lines

  Mention in the int() docstring that a base zero has meaning, as
  stated in http://docs.python.org/lib/built-in-funcs.html as well.
........
  r53341 | gustavo.niemeyer | 2007-01-10 17:15:48 +0100 (Wed, 10 Jan 2007) | 2 lines

  Minor change in int() docstring for proper spacing.
........
  r53358 | thomas.heller | 2007-01-10 21:12:13 +0100 (Wed, 10 Jan 2007) | 1 line

  Change the ctypes version number to "1.1.0".
........
  r53361 | thomas.heller | 2007-01-10 21:51:19 +0100 (Wed, 10 Jan 2007) | 1 line

  Must change the version number in the _ctypes extension as well.
........
  r53362 | guido.van.rossum | 2007-01-11 00:12:56 +0100 (Thu, 11 Jan 2007) | 3 lines

  Fix the signature of log_error().  (A subclass that did the right thing
  was getting complaints from pychecker.)
........
  r53370 | matthias.klose | 2007-01-11 11:26:31 +0100 (Thu, 11 Jan 2007) | 2 lines

  - Make the documentation match the code and the docstring
........
  r53375 | matthias.klose | 2007-01-11 12:44:04 +0100 (Thu, 11 Jan 2007) | 2 lines

  - idle: Honor the "Cancel" action in the save dialog (Debian bug #299092).
........
  r53381 | raymond.hettinger | 2007-01-11 19:22:55 +0100 (Thu, 11 Jan 2007) | 1 line

  SF #1486663 -- Allow keyword args in subclasses of set() and frozenset().
........
  r53388 | thomas.heller | 2007-01-11 22:18:56 +0100 (Thu, 11 Jan 2007) | 4 lines

  Fixes for 64-bit Windows: In ctypes.wintypes, correct the definitions
  of HANDLE, WPARAM, LPARAM data types.  Make parameterless foreign
  function calls work.
........
  r53390 | thomas.heller | 2007-01-11 22:23:12 +0100 (Thu, 11 Jan 2007) | 2 lines

  Correct the comments: the code is right.
........
  r53393 | brett.cannon | 2007-01-12 08:27:52 +0100 (Fri, 12 Jan 2007) | 3 lines

  Fix error where the end of a funcdesc environment was accidentally moved too
  far down.
........
  r53397 | anthony.baxter | 2007-01-12 10:35:56 +0100 (Fri, 12 Jan 2007) | 3 lines

  add parsetok.h as a dependency - previously, changing this file doesn't
  cause the right files to be rebuilt.
........
  r53401 | thomas.heller | 2007-01-12 21:08:19 +0100 (Fri, 12 Jan 2007) | 3 lines

  Avoid warnings in the test suite because ctypes.wintypes cannot be
  imported on non-windows systems.
........
  r53402 | thomas.heller | 2007-01-12 21:17:34 +0100 (Fri, 12 Jan 2007) | 6 lines

  patch #1610795: BSD version of ctypes.util.find_library, by Martin
  Kammerhofer.

  release25-maint backport candidate, but the release manager has to
  decide.
........
  r53403 | thomas.heller | 2007-01-12 21:21:53 +0100 (Fri, 12 Jan 2007) | 3 lines

  patch #1610795: BSD version of ctypes.util.find_library, by Martin
  Kammerhofer.
........
  r53406 | brett.cannon | 2007-01-13 01:29:49 +0100 (Sat, 13 Jan 2007) | 2 lines

  Deprecate the sets module.
........
  r53407 | georg.brandl | 2007-01-13 13:31:51 +0100 (Sat, 13 Jan 2007) | 3 lines

  Fix typo.
........
  r53409 | marc-andre.lemburg | 2007-01-13 22:00:08 +0100 (Sat, 13 Jan 2007) | 16 lines

  Bump version number and change copyright year.

  Add new API linux_distribution() which supports reading the full distribution
  name and also knows how to parse LSB-style release files.

  Redirect the old dist() API to the new API (using the short distribution name
  taken from the release file filename).

  Add branch and revision to _sys_version().

  Add work-around for Cygwin to libc_ver().

  Add support for IronPython (thanks for Anthony Baxter) and make
  Jython support more robust.
........
  r53410 | neal.norwitz | 2007-01-13 22:22:37 +0100 (Sat, 13 Jan 2007) | 1 line

  Fix grammar in docstrings
........
  r53411 | marc-andre.lemburg | 2007-01-13 23:32:21 +0100 (Sat, 13 Jan 2007) | 9 lines

  Add parameter sys_version to _sys_version().

  Change the cache for _sys_version() to take the parameter into account.

  Add support for parsing the IronPython 1.0.1 sys.version value - even
  though it still returns '1.0.0'; the version string no longer includes
  the patch level.
........
  r53412 | peter.astrand | 2007-01-13 23:35:35 +0100 (Sat, 13 Jan 2007) | 1 line

  Fix for bug #1634343: allow specifying empty arguments on Windows
........
  r53414 | marc-andre.lemburg | 2007-01-13 23:59:36 +0100 (Sat, 13 Jan 2007) | 14 lines

  Add Python implementation to the machine details.

  Pretty-print the Python version used for running PyBench.

  Let the user know when calibration has finished.

  [ 1563844 ] pybench support for IronPython:

  Simplify Unicode version detection.

  Make garbage collection and check interval settings optional if
  the Python implementation doesn't support thess (e.g. IronPython).
........
  r53415 | marc-andre.lemburg | 2007-01-14 00:13:54 +0100 (Sun, 14 Jan 2007) | 5 lines

  Use defaults if sys.executable isn't set (e.g. on Jython).

  This change allows running PyBench under Jython.
........
  r53416 | marc-andre.lemburg | 2007-01-14 00:15:33 +0100 (Sun, 14 Jan 2007) | 3 lines

  Jython doesn't have sys.setcheckinterval() - ignore it in that case.
........
  r53420 | gerhard.haering | 2007-01-14 02:43:50 +0100 (Sun, 14 Jan 2007) | 29 lines

  Merged changes from standalone version 2.3.3. This should probably all be
  merged into the 2.5 maintenance branch:

  - self->statement was not checked while fetching data, which could
    lead to crashes if you used the pysqlite API in unusual ways.
    Closing the cursor and continuing to fetch data was enough.

  - Converters are stored in a converters dictionary. The converter name
    is uppercased first. The old upper-casing algorithm was wrong and
    was replaced by a simple call to the Python string's upper() method
    instead.

  -Applied patch by Glyph Lefkowitz that fixes the problem with
   subsequent SQLITE_SCHEMA errors.

  - Improvement to the row type: rows can now be iterated over and have a keys()
    method. This improves compatibility with both tuple and dict a lot.

  - A bugfix for the subsecond resolution in timestamps.

  - Corrected the way the flags PARSE_DECLTYPES and PARSE_COLNAMES are
    checked for. Now they work as documented.

  - gcc on Linux sucks. It exports all symbols by default in shared
    libraries, so if symbols are not unique it can lead to problems with
    symbol lookup.  pysqlite used to crash under Apache when mod_cache
    was enabled because both modules had the symbol cache_init. I fixed
    this by applying the prefix pysqlite_ almost everywhere. Sigh.
........
  r53423 | guido.van.rossum | 2007-01-14 04:46:33 +0100 (Sun, 14 Jan 2007) | 2 lines

  Remove a dependency of this test on $COLUMNS.
........
  r53425 | ka-ping.yee | 2007-01-14 05:25:15 +0100 (Sun, 14 Jan 2007) | 3 lines

  Handle old-style instances more gracefully (display documentation on
  the relevant class instead of documentation on <type 'instance'>).
........
  r53440 | vinay.sajip | 2007-01-14 22:49:59 +0100 (Sun, 14 Jan 2007) | 1 line

  Added WatchedFileHandler (based on SF patch #1598415)
........
  r53441 | vinay.sajip | 2007-01-14 22:50:50 +0100 (Sun, 14 Jan 2007) | 1 line

  Added documentation for WatchedFileHandler (based on SF patch #1598415)
........
  r53442 | guido.van.rossum | 2007-01-15 01:02:35 +0100 (Mon, 15 Jan 2007) | 2 lines

  Doc patch matching r53434 (htonl etc. now always take/return positive ints).
........
2007-01-15 15:49:28 +00:00

1070 lines
33 KiB
C

/* cursor.c - the cursor type
*
* Copyright (C) 2004-2006 Gerhard Häring <gh@ghaering.de>
*
* This file is part of pysqlite.
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#include "cursor.h"
#include "module.h"
#include "util.h"
#include "sqlitecompat.h"
/* used to decide wether to call PyInt_FromLong or PyLong_FromLongLong */
#ifndef INT32_MIN
#define INT32_MIN (-2147483647 - 1)
#endif
#ifndef INT32_MAX
#define INT32_MAX 2147483647
#endif
PyObject* pysqlite_cursor_iternext(pysqlite_Cursor* self);
static pysqlite_StatementKind detect_statement_type(char* statement)
{
char buf[20];
char* src;
char* dst;
src = statement;
/* skip over whitepace */
while (*src == '\r' || *src == '\n' || *src == ' ' || *src == '\t') {
src++;
}
if (*src == 0)
return STATEMENT_INVALID;
dst = buf;
*dst = 0;
while (isalpha(*src) && dst - buf < sizeof(buf) - 2) {
*dst++ = tolower(*src++);
}
*dst = 0;
if (!strcmp(buf, "select")) {
return STATEMENT_SELECT;
} else if (!strcmp(buf, "insert")) {
return STATEMENT_INSERT;
} else if (!strcmp(buf, "update")) {
return STATEMENT_UPDATE;
} else if (!strcmp(buf, "delete")) {
return STATEMENT_DELETE;
} else if (!strcmp(buf, "replace")) {
return STATEMENT_REPLACE;
} else {
return STATEMENT_OTHER;
}
}
int pysqlite_cursor_init(pysqlite_Cursor* self, PyObject* args, PyObject* kwargs)
{
pysqlite_Connection* connection;
if (!PyArg_ParseTuple(args, "O!", &pysqlite_ConnectionType, &connection))
{
return -1;
}
Py_INCREF(connection);
self->connection = connection;
self->statement = NULL;
self->next_row = NULL;
self->row_cast_map = PyList_New(0);
if (!self->row_cast_map) {
return -1;
}
Py_INCREF(Py_None);
self->description = Py_None;
Py_INCREF(Py_None);
self->lastrowid= Py_None;
self->arraysize = 1;
self->rowcount = PyInt_FromLong(-1L);
if (!self->rowcount) {
return -1;
}
Py_INCREF(Py_None);
self->row_factory = Py_None;
if (!pysqlite_check_thread(self->connection)) {
return -1;
}
return 0;
}
void pysqlite_cursor_dealloc(pysqlite_Cursor* self)
{
int rc;
/* Reset the statement if the user has not closed the cursor */
if (self->statement) {
rc = pysqlite_statement_reset(self->statement);
Py_DECREF(self->statement);
}
Py_XDECREF(self->connection);
Py_XDECREF(self->row_cast_map);
Py_XDECREF(self->description);
Py_XDECREF(self->lastrowid);
Py_XDECREF(self->rowcount);
Py_XDECREF(self->row_factory);
Py_XDECREF(self->next_row);
self->ob_type->tp_free((PyObject*)self);
}
PyObject* _pysqlite_get_converter(PyObject* key)
{
PyObject* upcase_key;
PyObject* retval;
upcase_key = PyObject_CallMethod(key, "upper", "");
if (!upcase_key) {
return NULL;
}
retval = PyDict_GetItem(converters, upcase_key);
Py_DECREF(upcase_key);
return retval;
}
int pysqlite_build_row_cast_map(pysqlite_Cursor* self)
{
int i;
const char* type_start = (const char*)-1;
const char* pos;
const char* colname;
const char* decltype;
PyObject* py_decltype;
PyObject* converter;
PyObject* key;
if (!self->connection->detect_types) {
return 0;
}
Py_XDECREF(self->row_cast_map);
self->row_cast_map = PyList_New(0);
for (i = 0; i < sqlite3_column_count(self->statement->st); i++) {
converter = NULL;
if (self->connection->detect_types & PARSE_COLNAMES) {
colname = sqlite3_column_name(self->statement->st, i);
if (colname) {
for (pos = colname; *pos != 0; pos++) {
if (*pos == '[') {
type_start = pos + 1;
} else if (*pos == ']' && type_start != (const char*)-1) {
key = PyString_FromStringAndSize(type_start, pos - type_start);
if (!key) {
/* creating a string failed, but it is too complicated
* to propagate the error here, we just assume there is
* no converter and proceed */
break;
}
converter = _pysqlite_get_converter(key);
Py_DECREF(key);
break;
}
}
}
}
if (!converter && self->connection->detect_types & PARSE_DECLTYPES) {
decltype = sqlite3_column_decltype(self->statement->st, i);
if (decltype) {
for (pos = decltype;;pos++) {
if (*pos == ' ' || *pos == 0) {
py_decltype = PyString_FromStringAndSize(decltype, pos - decltype);
if (!py_decltype) {
return -1;
}
break;
}
}
converter = _pysqlite_get_converter(py_decltype);
Py_DECREF(py_decltype);
}
}
if (!converter) {
converter = Py_None;
}
if (PyList_Append(self->row_cast_map, converter) != 0) {
if (converter != Py_None) {
Py_DECREF(converter);
}
Py_XDECREF(self->row_cast_map);
self->row_cast_map = NULL;
return -1;
}
}
return 0;
}
PyObject* _pysqlite_build_column_name(const char* colname)
{
const char* pos;
if (!colname) {
Py_INCREF(Py_None);
return Py_None;
}
for (pos = colname;; pos++) {
if (*pos == 0 || *pos == '[') {
if ((*pos == '[') && (pos > colname) && (*(pos-1) == ' ')) {
pos--;
}
return PyString_FromStringAndSize(colname, pos - colname);
}
}
}
PyObject* pysqlite_unicode_from_string(const char* val_str, int optimize)
{
const char* check;
int is_ascii = 0;
if (optimize) {
is_ascii = 1;
check = val_str;
while (*check) {
if (*check & 0x80) {
is_ascii = 0;
break;
}
check++;
}
}
if (is_ascii) {
return PyString_FromString(val_str);
} else {
return PyUnicode_DecodeUTF8(val_str, strlen(val_str), NULL);
}
}
/*
* Returns a row from the currently active SQLite statement
*
* Precondidition:
* - sqlite3_step() has been called before and it returned SQLITE_ROW.
*/
PyObject* _pysqlite_fetch_one_row(pysqlite_Cursor* self)
{
int i, numcols;
PyObject* row;
PyObject* item = NULL;
int coltype;
PY_LONG_LONG intval;
PyObject* converter;
PyObject* converted;
Py_ssize_t nbytes;
PyObject* buffer;
void* raw_buffer;
const char* val_str;
char buf[200];
const char* colname;
Py_BEGIN_ALLOW_THREADS
numcols = sqlite3_data_count(self->statement->st);
Py_END_ALLOW_THREADS
row = PyTuple_New(numcols);
if (!row) {
return NULL;
}
for (i = 0; i < numcols; i++) {
if (self->connection->detect_types) {
converter = PyList_GetItem(self->row_cast_map, i);
if (!converter) {
converter = Py_None;
}
} else {
converter = Py_None;
}
if (converter != Py_None) {
nbytes = sqlite3_column_bytes(self->statement->st, i);
val_str = (const char*)sqlite3_column_blob(self->statement->st, i);
if (!val_str) {
Py_INCREF(Py_None);
converted = Py_None;
} else {
item = PyString_FromStringAndSize(val_str, nbytes);
if (!item) {
return NULL;
}
converted = PyObject_CallFunction(converter, "O", item);
Py_DECREF(item);
if (!converted) {
break;
}
}
} else {
Py_BEGIN_ALLOW_THREADS
coltype = sqlite3_column_type(self->statement->st, i);
Py_END_ALLOW_THREADS
if (coltype == SQLITE_NULL) {
Py_INCREF(Py_None);
converted = Py_None;
} else if (coltype == SQLITE_INTEGER) {
intval = sqlite3_column_int64(self->statement->st, i);
if (intval < INT32_MIN || intval > INT32_MAX) {
converted = PyLong_FromLongLong(intval);
} else {
converted = PyInt_FromLong((long)intval);
}
} else if (coltype == SQLITE_FLOAT) {
converted = PyFloat_FromDouble(sqlite3_column_double(self->statement->st, i));
} else if (coltype == SQLITE_TEXT) {
val_str = (const char*)sqlite3_column_text(self->statement->st, i);
if ((self->connection->text_factory == (PyObject*)&PyUnicode_Type)
|| (self->connection->text_factory == pysqlite_OptimizedUnicode)) {
converted = pysqlite_unicode_from_string(val_str,
self->connection->text_factory == pysqlite_OptimizedUnicode ? 1 : 0);
if (!converted) {
colname = sqlite3_column_name(self->statement->st, i);
if (!colname) {
colname = "<unknown column name>";
}
PyOS_snprintf(buf, sizeof(buf) - 1, "Could not decode to UTF-8 column '%s' with text '%s'",
colname , val_str);
PyErr_SetString(pysqlite_OperationalError, buf);
}
} else if (self->connection->text_factory == (PyObject*)&PyString_Type) {
converted = PyString_FromString(val_str);
} else {
converted = PyObject_CallFunction(self->connection->text_factory, "s", val_str);
}
} else {
/* coltype == SQLITE_BLOB */
nbytes = sqlite3_column_bytes(self->statement->st, i);
buffer = PyBuffer_New(nbytes);
if (!buffer) {
break;
}
if (PyObject_AsWriteBuffer(buffer, &raw_buffer, &nbytes)) {
break;
}
memcpy(raw_buffer, sqlite3_column_blob(self->statement->st, i), nbytes);
converted = buffer;
}
}
if (converted) {
PyTuple_SetItem(row, i, converted);
} else {
Py_INCREF(Py_None);
PyTuple_SetItem(row, i, Py_None);
}
}
if (PyErr_Occurred()) {
Py_DECREF(row);
row = NULL;
}
return row;
}
PyObject* _pysqlite_query_execute(pysqlite_Cursor* self, int multiple, PyObject* args)
{
PyObject* operation;
PyObject* operation_bytestr = NULL;
char* operation_cstr;
PyObject* parameters_list = NULL;
PyObject* parameters_iter = NULL;
PyObject* parameters = NULL;
int i;
int rc;
PyObject* func_args;
PyObject* result;
int numcols;
PY_LONG_LONG lastrowid;
int statement_type;
PyObject* descriptor;
PyObject* second_argument = NULL;
long rowcount = 0;
if (!pysqlite_check_thread(self->connection) || !pysqlite_check_connection(self->connection)) {
return NULL;
}
Py_XDECREF(self->next_row);
self->next_row = NULL;
if (multiple) {
/* executemany() */
if (!PyArg_ParseTuple(args, "OO", &operation, &second_argument)) {
return NULL;
}
if (!PyString_Check(operation) && !PyUnicode_Check(operation)) {
PyErr_SetString(PyExc_ValueError, "operation parameter must be str or unicode");
return NULL;
}
if (PyIter_Check(second_argument)) {
/* iterator */
Py_INCREF(second_argument);
parameters_iter = second_argument;
} else {
/* sequence */
parameters_iter = PyObject_GetIter(second_argument);
if (!parameters_iter) {
return NULL;
}
}
} else {
/* execute() */
if (!PyArg_ParseTuple(args, "O|O", &operation, &second_argument)) {
return NULL;
}
if (!PyString_Check(operation) && !PyUnicode_Check(operation)) {
PyErr_SetString(PyExc_ValueError, "operation parameter must be str or unicode");
return NULL;
}
parameters_list = PyList_New(0);
if (!parameters_list) {
return NULL;
}
if (second_argument == NULL) {
second_argument = PyTuple_New(0);
if (!second_argument) {
goto error;
}
} else {
Py_INCREF(second_argument);
}
if (PyList_Append(parameters_list, second_argument) != 0) {
Py_DECREF(second_argument);
goto error;
}
Py_DECREF(second_argument);
parameters_iter = PyObject_GetIter(parameters_list);
if (!parameters_iter) {
goto error;
}
}
if (self->statement != NULL) {
/* There is an active statement */
rc = pysqlite_statement_reset(self->statement);
}
if (PyString_Check(operation)) {
operation_cstr = PyString_AsString(operation);
} else {
operation_bytestr = PyUnicode_AsUTF8String(operation);
if (!operation_bytestr) {
goto error;
}
operation_cstr = PyString_AsString(operation_bytestr);
}
/* reset description and rowcount */
Py_DECREF(self->description);
Py_INCREF(Py_None);
self->description = Py_None;
Py_DECREF(self->rowcount);
self->rowcount = PyInt_FromLong(-1L);
if (!self->rowcount) {
goto error;
}
statement_type = detect_statement_type(operation_cstr);
if (self->connection->begin_statement) {
switch (statement_type) {
case STATEMENT_UPDATE:
case STATEMENT_DELETE:
case STATEMENT_INSERT:
case STATEMENT_REPLACE:
if (!self->connection->inTransaction) {
result = _pysqlite_connection_begin(self->connection);
if (!result) {
goto error;
}
Py_DECREF(result);
}
break;
case STATEMENT_OTHER:
/* it's a DDL statement or something similar
- we better COMMIT first so it works for all cases */
if (self->connection->inTransaction) {
result = pysqlite_connection_commit(self->connection, NULL);
if (!result) {
goto error;
}
Py_DECREF(result);
}
break;
case STATEMENT_SELECT:
if (multiple) {
PyErr_SetString(pysqlite_ProgrammingError,
"You cannot execute SELECT statements in executemany().");
goto error;
}
break;
}
}
func_args = PyTuple_New(1);
if (!func_args) {
goto error;
}
Py_INCREF(operation);
if (PyTuple_SetItem(func_args, 0, operation) != 0) {
goto error;
}
if (self->statement) {
(void)pysqlite_statement_reset(self->statement);
Py_DECREF(self->statement);
}
self->statement = (pysqlite_Statement*)pysqlite_cache_get(self->connection->statement_cache, func_args);
Py_DECREF(func_args);
if (!self->statement) {
goto error;
}
if (self->statement->in_use) {
Py_DECREF(self->statement);
self->statement = PyObject_New(pysqlite_Statement, &pysqlite_StatementType);
if (!self->statement) {
goto error;
}
rc = pysqlite_statement_create(self->statement, self->connection, operation);
if (rc != SQLITE_OK) {
self->statement = 0;
goto error;
}
}
pysqlite_statement_reset(self->statement);
pysqlite_statement_mark_dirty(self->statement);
while (1) {
parameters = PyIter_Next(parameters_iter);
if (!parameters) {
break;
}
pysqlite_statement_mark_dirty(self->statement);
pysqlite_statement_bind_parameters(self->statement, parameters);
if (PyErr_Occurred()) {
goto error;
}
if (pysqlite_build_row_cast_map(self) != 0) {
PyErr_SetString(pysqlite_OperationalError, "Error while building row_cast_map");
goto error;
}
/* Keep trying the SQL statement until the schema stops changing. */
while (1) {
/* Actually execute the SQL statement. */
rc = _sqlite_step_with_busyhandler(self->statement->st, self->connection);
if (rc == SQLITE_DONE || rc == SQLITE_ROW) {
/* If it worked, let's get out of the loop */
break;
}
/* Something went wrong. Re-set the statement and try again. */
rc = pysqlite_statement_reset(self->statement);
if (rc == SQLITE_SCHEMA) {
/* If this was a result of the schema changing, let's try
again. */
rc = pysqlite_statement_recompile(self->statement, parameters);
if (rc == SQLITE_OK) {
continue;
} else {
/* If the database gave us an error, promote it to Python. */
_pysqlite_seterror(self->connection->db);
goto error;
}
} else {
if (PyErr_Occurred()) {
/* there was an error that occurred in a user-defined callback */
if (_enable_callback_tracebacks) {
PyErr_Print();
} else {
PyErr_Clear();
}
}
_pysqlite_seterror(self->connection->db);
goto error;
}
}
if (rc == SQLITE_ROW || (rc == SQLITE_DONE && statement_type == STATEMENT_SELECT)) {
Py_BEGIN_ALLOW_THREADS
numcols = sqlite3_column_count(self->statement->st);
Py_END_ALLOW_THREADS
if (self->description == Py_None) {
Py_DECREF(self->description);
self->description = PyTuple_New(numcols);
if (!self->description) {
goto error;
}
for (i = 0; i < numcols; i++) {
descriptor = PyTuple_New(7);
if (!descriptor) {
goto error;
}
PyTuple_SetItem(descriptor, 0, _pysqlite_build_column_name(sqlite3_column_name(self->statement->st, i)));
Py_INCREF(Py_None); PyTuple_SetItem(descriptor, 1, Py_None);
Py_INCREF(Py_None); PyTuple_SetItem(descriptor, 2, Py_None);
Py_INCREF(Py_None); PyTuple_SetItem(descriptor, 3, Py_None);
Py_INCREF(Py_None); PyTuple_SetItem(descriptor, 4, Py_None);
Py_INCREF(Py_None); PyTuple_SetItem(descriptor, 5, Py_None);
Py_INCREF(Py_None); PyTuple_SetItem(descriptor, 6, Py_None);
PyTuple_SetItem(self->description, i, descriptor);
}
}
}
if (rc == SQLITE_ROW) {
if (multiple) {
PyErr_SetString(pysqlite_ProgrammingError, "executemany() can only execute DML statements.");
goto error;
}
self->next_row = _pysqlite_fetch_one_row(self);
} else if (rc == SQLITE_DONE && !multiple) {
pysqlite_statement_reset(self->statement);
Py_DECREF(self->statement);
self->statement = 0;
}
switch (statement_type) {
case STATEMENT_UPDATE:
case STATEMENT_DELETE:
case STATEMENT_INSERT:
case STATEMENT_REPLACE:
Py_BEGIN_ALLOW_THREADS
rowcount += (long)sqlite3_changes(self->connection->db);
Py_END_ALLOW_THREADS
Py_DECREF(self->rowcount);
self->rowcount = PyInt_FromLong(rowcount);
}
Py_DECREF(self->lastrowid);
if (statement_type == STATEMENT_INSERT) {
Py_BEGIN_ALLOW_THREADS
lastrowid = sqlite3_last_insert_rowid(self->connection->db);
Py_END_ALLOW_THREADS
self->lastrowid = PyInt_FromLong((long)lastrowid);
} else {
Py_INCREF(Py_None);
self->lastrowid = Py_None;
}
if (multiple) {
rc = pysqlite_statement_reset(self->statement);
}
Py_XDECREF(parameters);
}
error:
Py_XDECREF(operation_bytestr);
Py_XDECREF(parameters);
Py_XDECREF(parameters_iter);
Py_XDECREF(parameters_list);
if (PyErr_Occurred()) {
return NULL;
} else {
Py_INCREF(self);
return (PyObject*)self;
}
}
PyObject* pysqlite_cursor_execute(pysqlite_Cursor* self, PyObject* args)
{
return _pysqlite_query_execute(self, 0, args);
}
PyObject* pysqlite_cursor_executemany(pysqlite_Cursor* self, PyObject* args)
{
return _pysqlite_query_execute(self, 1, args);
}
PyObject* pysqlite_cursor_executescript(pysqlite_Cursor* self, PyObject* args)
{
PyObject* script_obj;
PyObject* script_str = NULL;
const char* script_cstr;
sqlite3_stmt* statement;
int rc;
PyObject* result;
int statement_completed = 0;
if (!PyArg_ParseTuple(args, "O", &script_obj)) {
return NULL;
}
if (!pysqlite_check_thread(self->connection) || !pysqlite_check_connection(self->connection)) {
return NULL;
}
if (PyString_Check(script_obj)) {
script_cstr = PyString_AsString(script_obj);
} else if (PyUnicode_Check(script_obj)) {
script_str = PyUnicode_AsUTF8String(script_obj);
if (!script_str) {
return NULL;
}
script_cstr = PyString_AsString(script_str);
} else {
PyErr_SetString(PyExc_ValueError, "script argument must be unicode or string.");
return NULL;
}
/* commit first */
result = pysqlite_connection_commit(self->connection, NULL);
if (!result) {
goto error;
}
Py_DECREF(result);
while (1) {
if (!sqlite3_complete(script_cstr)) {
break;
}
statement_completed = 1;
rc = sqlite3_prepare(self->connection->db,
script_cstr,
-1,
&statement,
&script_cstr);
if (rc != SQLITE_OK) {
_pysqlite_seterror(self->connection->db);
goto error;
}
/* execute statement, and ignore results of SELECT statements */
rc = SQLITE_ROW;
while (rc == SQLITE_ROW) {
rc = _sqlite_step_with_busyhandler(statement, self->connection);
}
if (rc != SQLITE_DONE) {
(void)sqlite3_finalize(statement);
_pysqlite_seterror(self->connection->db);
goto error;
}
rc = sqlite3_finalize(statement);
if (rc != SQLITE_OK) {
_pysqlite_seterror(self->connection->db);
goto error;
}
}
error:
Py_XDECREF(script_str);
if (!statement_completed) {
PyErr_SetString(pysqlite_ProgrammingError, "you did not provide a complete SQL statement");
}
if (PyErr_Occurred()) {
return NULL;
} else {
Py_INCREF(self);
return (PyObject*)self;
}
}
PyObject* pysqlite_cursor_getiter(pysqlite_Cursor *self)
{
Py_INCREF(self);
return (PyObject*)self;
}
PyObject* pysqlite_cursor_iternext(pysqlite_Cursor *self)
{
PyObject* next_row_tuple;
PyObject* next_row;
int rc;
if (!pysqlite_check_thread(self->connection) || !pysqlite_check_connection(self->connection)) {
return NULL;
}
if (!self->next_row) {
if (self->statement) {
(void)pysqlite_statement_reset(self->statement);
Py_DECREF(self->statement);
self->statement = NULL;
}
return NULL;
}
next_row_tuple = self->next_row;
self->next_row = NULL;
if (self->row_factory != Py_None) {
next_row = PyObject_CallFunction(self->row_factory, "OO", self, next_row_tuple);
Py_DECREF(next_row_tuple);
} else {
next_row = next_row_tuple;
}
if (self->statement) {
rc = _sqlite_step_with_busyhandler(self->statement->st, self->connection);
if (rc != SQLITE_DONE && rc != SQLITE_ROW) {
Py_DECREF(next_row);
_pysqlite_seterror(self->connection->db);
return NULL;
}
if (rc == SQLITE_ROW) {
self->next_row = _pysqlite_fetch_one_row(self);
}
}
return next_row;
}
PyObject* pysqlite_cursor_fetchone(pysqlite_Cursor* self, PyObject* args)
{
PyObject* row;
row = pysqlite_cursor_iternext(self);
if (!row && !PyErr_Occurred()) {
Py_INCREF(Py_None);
return Py_None;
}
return row;
}
PyObject* pysqlite_cursor_fetchmany(pysqlite_Cursor* self, PyObject* args)
{
PyObject* row;
PyObject* list;
int maxrows = self->arraysize;
int counter = 0;
if (!PyArg_ParseTuple(args, "|i", &maxrows)) {
return NULL;
}
list = PyList_New(0);
if (!list) {
return NULL;
}
/* just make sure we enter the loop */
row = Py_None;
while (row) {
row = pysqlite_cursor_iternext(self);
if (row) {
PyList_Append(list, row);
Py_DECREF(row);
} else {
break;
}
if (++counter == maxrows) {
break;
}
}
if (PyErr_Occurred()) {
Py_DECREF(list);
return NULL;
} else {
return list;
}
}
PyObject* pysqlite_cursor_fetchall(pysqlite_Cursor* self, PyObject* args)
{
PyObject* row;
PyObject* list;
list = PyList_New(0);
if (!list) {
return NULL;
}
/* just make sure we enter the loop */
row = (PyObject*)Py_None;
while (row) {
row = pysqlite_cursor_iternext(self);
if (row) {
PyList_Append(list, row);
Py_DECREF(row);
}
}
if (PyErr_Occurred()) {
Py_DECREF(list);
return NULL;
} else {
return list;
}
}
PyObject* pysqlite_noop(pysqlite_Connection* self, PyObject* args)
{
/* don't care, return None */
Py_INCREF(Py_None);
return Py_None;
}
PyObject* pysqlite_cursor_close(pysqlite_Cursor* self, PyObject* args)
{
if (!pysqlite_check_thread(self->connection) || !pysqlite_check_connection(self->connection)) {
return NULL;
}
if (self->statement) {
(void)pysqlite_statement_reset(self->statement);
Py_DECREF(self->statement);
self->statement = 0;
}
Py_INCREF(Py_None);
return Py_None;
}
static PyMethodDef cursor_methods[] = {
{"execute", (PyCFunction)pysqlite_cursor_execute, METH_VARARGS,
PyDoc_STR("Executes a SQL statement.")},
{"executemany", (PyCFunction)pysqlite_cursor_executemany, METH_VARARGS,
PyDoc_STR("Repeatedly executes a SQL statement.")},
{"executescript", (PyCFunction)pysqlite_cursor_executescript, METH_VARARGS,
PyDoc_STR("Executes a multiple SQL statements at once. Non-standard.")},
{"fetchone", (PyCFunction)pysqlite_cursor_fetchone, METH_NOARGS,
PyDoc_STR("Fetches several rows from the resultset.")},
{"fetchmany", (PyCFunction)pysqlite_cursor_fetchmany, METH_VARARGS,
PyDoc_STR("Fetches all rows from the resultset.")},
{"fetchall", (PyCFunction)pysqlite_cursor_fetchall, METH_NOARGS,
PyDoc_STR("Fetches one row from the resultset.")},
{"close", (PyCFunction)pysqlite_cursor_close, METH_NOARGS,
PyDoc_STR("Closes the cursor.")},
{"setinputsizes", (PyCFunction)pysqlite_noop, METH_VARARGS,
PyDoc_STR("Required by DB-API. Does nothing in pysqlite.")},
{"setoutputsize", (PyCFunction)pysqlite_noop, METH_VARARGS,
PyDoc_STR("Required by DB-API. Does nothing in pysqlite.")},
{NULL, NULL}
};
static struct PyMemberDef cursor_members[] =
{
{"connection", T_OBJECT, offsetof(pysqlite_Cursor, connection), RO},
{"description", T_OBJECT, offsetof(pysqlite_Cursor, description), RO},
{"arraysize", T_INT, offsetof(pysqlite_Cursor, arraysize), 0},
{"lastrowid", T_OBJECT, offsetof(pysqlite_Cursor, lastrowid), RO},
{"rowcount", T_OBJECT, offsetof(pysqlite_Cursor, rowcount), RO},
{"row_factory", T_OBJECT, offsetof(pysqlite_Cursor, row_factory), 0},
{NULL}
};
static char cursor_doc[] =
PyDoc_STR("SQLite database cursor class.");
PyTypeObject pysqlite_CursorType = {
PyObject_HEAD_INIT(NULL)
0, /* ob_size */
MODULE_NAME ".Cursor", /* tp_name */
sizeof(pysqlite_Cursor), /* tp_basicsize */
0, /* tp_itemsize */
(destructor)pysqlite_cursor_dealloc, /* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_compare */
0, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
0, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
cursor_doc, /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
(getiterfunc)pysqlite_cursor_getiter, /* tp_iter */
(iternextfunc)pysqlite_cursor_iternext, /* tp_iternext */
cursor_methods, /* tp_methods */
cursor_members, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
(initproc)pysqlite_cursor_init, /* tp_init */
0, /* tp_alloc */
0, /* tp_new */
0 /* tp_free */
};
extern int pysqlite_cursor_setup_types(void)
{
pysqlite_CursorType.tp_new = PyType_GenericNew;
return PyType_Ready(&pysqlite_CursorType);
}