summaryrefslogtreecommitdiffstats
path: root/Modules
diff options
context:
space:
mode:
authorAnthony Baxter <anthonybaxter@gmail.com>2006-04-01 00:57:31 (GMT)
committerAnthony Baxter <anthonybaxter@gmail.com>2006-04-01 00:57:31 (GMT)
commitc51ee69b27a35bb45e501766dd33674eae7ddb30 (patch)
tree7853c32c266a623463cdd632178a298b1c0e53a1 /Modules
parentc17976e9833f3093adb1019356737e728a24f7c9 (diff)
downloadcpython-c51ee69b27a35bb45e501766dd33674eae7ddb30.zip
cpython-c51ee69b27a35bb45e501766dd33674eae7ddb30.tar.gz
cpython-c51ee69b27a35bb45e501766dd33674eae7ddb30.tar.bz2
merged the sqlite-integration branch.
This is based on pysqlite2.1.3, and provides a DB-API interface in the standard library. You'll need sqlite 3.2.2 or later to build this - if you have an earlier version, the C extension module will not be built.
Diffstat (limited to 'Modules')
-rw-r--r--Modules/_sqlite/adapters.c40
-rw-r--r--Modules/_sqlite/adapters.h33
-rw-r--r--Modules/_sqlite/cache.c343
-rw-r--r--Modules/_sqlite/cache.h61
-rw-r--r--Modules/_sqlite/connection.c922
-rw-r--r--Modules/_sqlite/connection.h103
-rw-r--r--Modules/_sqlite/converters.c40
-rw-r--r--Modules/_sqlite/converters.h33
-rw-r--r--Modules/_sqlite/cursor.c1067
-rw-r--r--Modules/_sqlite/cursor.h71
-rw-r--r--Modules/_sqlite/microprotocols.c141
-rw-r--r--Modules/_sqlite/microprotocols.h59
-rw-r--r--Modules/_sqlite/module.c290
-rw-r--r--Modules/_sqlite/module.h53
-rw-r--r--Modules/_sqlite/prepare_protocol.c84
-rw-r--r--Modules/_sqlite/prepare_protocol.h41
-rw-r--r--Modules/_sqlite/row.c195
-rw-r--r--Modules/_sqlite/row.h39
-rw-r--r--Modules/_sqlite/statement.c285
-rw-r--r--Modules/_sqlite/statement.h55
-rw-r--r--Modules/_sqlite/util.c147
-rw-r--r--Modules/_sqlite/util.h40
22 files changed, 4142 insertions, 0 deletions
diff --git a/Modules/_sqlite/adapters.c b/Modules/_sqlite/adapters.c
new file mode 100644
index 0000000..e6fde03
--- /dev/null
+++ b/Modules/_sqlite/adapters.c
@@ -0,0 +1,40 @@
+/* adapters.c - default adapters
+ *
+ * Copyright (C) 2005 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 "util.h"
+#include "module.h"
+#include "adapters.h"
+
+/* dummy, will be implemented in a later version */
+
+PyObject* adapt_date(PyObject* self, PyObject* args, PyObject* kwargs)
+{
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+PyObject* adapt_datetime(PyObject* self, PyObject* args, PyObject* kwargs)
+{
+ Py_INCREF(Py_None);
+ return Py_None;
+}
diff --git a/Modules/_sqlite/adapters.h b/Modules/_sqlite/adapters.h
new file mode 100644
index 0000000..d2e8479
--- /dev/null
+++ b/Modules/_sqlite/adapters.h
@@ -0,0 +1,33 @@
+/* adapters.h - default adapters
+ *
+ * Copyright (C) 2005 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.
+ */
+
+#ifndef PYSQLITE_ADAPTERS_H
+#define PYSQLITE_ADAPTERS_H
+#include "Python.h"
+#include "pythread.h"
+#include "sqlite3.h"
+
+PyObject* adapt_date(PyObject* self, PyObject* args, PyObject* kwargs);
+PyObject* adapt_datetime(PyObject* self, PyObject* args, PyObject* kwargs);
+
+#endif
diff --git a/Modules/_sqlite/cache.c b/Modules/_sqlite/cache.c
new file mode 100644
index 0000000..0c7d4a3
--- /dev/null
+++ b/Modules/_sqlite/cache.c
@@ -0,0 +1,343 @@
+/* cache .c - a LRU cache
+ *
+ * Copyright (C) 2004-2005 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 "cache.h"
+
+/* only used internally */
+Node* new_node(PyObject* key, PyObject* data)
+{
+ Node* node;
+
+ node = (Node*) (NodeType.tp_alloc(&NodeType, 0));
+ /*node = PyObject_New(Node, &NodeType);*/
+ if (!node) {
+ return NULL;
+ }
+
+ Py_INCREF(key);
+ node->key = key;
+
+ Py_INCREF(data);
+ node->data = data;
+
+ node->prev = NULL;
+ node->next = NULL;
+
+ return node;
+}
+
+void node_dealloc(Node* self)
+{
+ Py_DECREF(self->key);
+ Py_DECREF(self->data);
+
+ self->ob_type->tp_free((PyObject*)self);
+}
+
+int cache_init(Cache* self, PyObject* args, PyObject* kwargs)
+{
+ PyObject* factory;
+ int size = 10;
+
+ self->factory = NULL;
+
+ if (!PyArg_ParseTuple(args, "O|i", &factory, &size))
+ {
+ return -1;
+ }
+
+ if (size < 5) {
+ size = 5;
+ }
+ self->size = size;
+ self->first = NULL;
+ self->last = NULL;
+ self->mapping = PyDict_New();
+ Py_INCREF(factory);
+ self->factory = factory;
+
+ self->decref_factory = 1;
+
+ return 0;
+}
+
+void cache_dealloc(Cache* self)
+{
+ Node* node;
+ Node* delete_node;
+
+ if (!self->factory) {
+ /* constructor failed, just get out of here */
+ return;
+ }
+
+ node = self->first;
+ while (node) {
+ delete_node = node;
+ node = node->next;
+ Py_DECREF(delete_node);
+ }
+
+ if (self->decref_factory) {
+ Py_DECREF(self->factory);
+ }
+ Py_DECREF(self->mapping);
+
+ self->ob_type->tp_free((PyObject*)self);
+}
+
+PyObject* cache_get(Cache* self, PyObject* args)
+{
+ PyObject* key;
+ Node* node;
+ Node* ptr;
+ PyObject* data;
+
+ if (!PyArg_ParseTuple(args, "O", &key))
+ {
+ return NULL;
+ }
+
+ node = (Node*)PyDict_GetItem(self->mapping, key);
+ if (node) {
+ node->count++;
+ if (node->prev && node->count > node->prev->count) {
+ ptr = node->prev;
+
+ while (ptr->prev && node->count > ptr->prev->count) {
+ ptr = ptr->prev;
+ }
+
+ if (node->next) {
+ node->next->prev = node->prev;
+ } else {
+ self->last = node->prev;
+ }
+ if (node->prev) {
+ node->prev->next = node->next;
+ }
+ if (ptr->prev) {
+ ptr->prev->next = node;
+ } else {
+ self->first = node;
+ }
+
+ node->next = ptr;
+ node->prev = ptr->prev;
+ if (!node->prev) {
+ self->first = node;
+ }
+ ptr->prev = node;
+ }
+ } else {
+ if (PyDict_Size(self->mapping) == self->size) {
+ if (self->last) {
+ node = self->last;
+ PyDict_DelItem(self->mapping, self->last->key);
+ if (node->prev) {
+ node->prev->next = NULL;
+ }
+ self->last = node->prev;
+ node->prev = NULL;
+
+ Py_DECREF(node);
+ }
+ }
+
+ data = PyObject_CallFunction(self->factory, "O", key);
+
+ if (!data) {
+ return NULL;
+ }
+
+ node = new_node(key, data);
+ node->prev = self->last;
+
+ Py_DECREF(data);
+
+ if (self->last) {
+ self->last->next = node;
+ } else {
+ self->first = node;
+ }
+ self->last = node;
+ PyDict_SetItem(self->mapping, key, (PyObject*)node);
+ }
+
+ Py_INCREF(node->data);
+ return node->data;
+}
+
+PyObject* cache_display(Cache* self, PyObject* args)
+{
+ Node* ptr;
+ PyObject* prevkey;
+ PyObject* nextkey;
+ PyObject* fmt_args;
+ PyObject* template;
+ PyObject* display_str;
+
+ ptr = self->first;
+
+ while (ptr) {
+ if (ptr->prev) {
+ prevkey = ptr->prev->key;
+ } else {
+ prevkey = Py_None;
+ }
+ Py_INCREF(prevkey);
+
+ if (ptr->next) {
+ nextkey = ptr->next->key;
+ } else {
+ nextkey = Py_None;
+ }
+ Py_INCREF(nextkey);
+
+ fmt_args = Py_BuildValue("OOO", prevkey, ptr->key, nextkey);
+ template = PyString_FromString("%s <- %s ->%s\n");
+ display_str = PyString_Format(template, fmt_args);
+ Py_DECREF(template);
+ Py_DECREF(fmt_args);
+ PyObject_Print(display_str, stdout, Py_PRINT_RAW);
+ Py_DECREF(display_str);
+
+ Py_DECREF(prevkey);
+ Py_DECREF(nextkey);
+
+ ptr = ptr->next;
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyMethodDef cache_methods[] = {
+ {"get", (PyCFunction)cache_get, METH_VARARGS,
+ PyDoc_STR("Gets an entry from the cache.")},
+ {"display", (PyCFunction)cache_display, METH_NOARGS,
+ PyDoc_STR("For debugging only.")},
+ {NULL, NULL}
+};
+
+PyTypeObject NodeType = {
+ PyObject_HEAD_INIT(NULL)
+ 0, /* ob_size */
+ "pysqlite2.dbapi2.Node", /* tp_name */
+ sizeof(Node), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)node_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 */
+ 0, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)0, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+ 0 /* tp_free */
+};
+
+PyTypeObject CacheType = {
+ PyObject_HEAD_INIT(NULL)
+ 0, /* ob_size */
+ "pysqlite2.dbapi2.Cache", /* tp_name */
+ sizeof(Cache), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)cache_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 */
+ 0, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ cache_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)cache_init, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+ 0 /* tp_free */
+};
+
+extern int cache_setup_types(void)
+{
+ int rc;
+
+ NodeType.tp_new = PyType_GenericNew;
+ CacheType.tp_new = PyType_GenericNew;
+
+ rc = PyType_Ready(&NodeType);
+ if (rc < 0) {
+ return rc;
+ }
+
+ rc = PyType_Ready(&CacheType);
+ return rc;
+}
diff --git a/Modules/_sqlite/cache.h b/Modules/_sqlite/cache.h
new file mode 100644
index 0000000..5cc16f3
--- /dev/null
+++ b/Modules/_sqlite/cache.h
@@ -0,0 +1,61 @@
+/* cache.h - definitions for the LRU cache
+ *
+ * Copyright (C) 2004-2005 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.
+ */
+
+#ifndef PYSQLITE_CACHE_H
+#define PYSQLITE_CACHE_H
+#include "Python.h"
+
+typedef struct _Node
+{
+ PyObject_HEAD
+ PyObject* key;
+ PyObject* data;
+ long count;
+ struct _Node* prev;
+ struct _Node* next;
+} Node;
+
+typedef struct
+{
+ PyObject_HEAD
+ int size;
+ PyObject* mapping;
+ PyObject* factory;
+ Node* first;
+ Node* last;
+ int decref_factory;
+} Cache;
+
+extern PyTypeObject NodeType;
+extern PyTypeObject CacheType;
+
+int node_init(Node* self, PyObject* args, PyObject* kwargs);
+void node_dealloc(Node* self);
+
+int cache_init(Cache* self, PyObject* args, PyObject* kwargs);
+void cache_dealloc(Cache* self);
+PyObject* cache_get(Cache* self, PyObject* args);
+
+int cache_setup_types(void);
+
+#endif
diff --git a/Modules/_sqlite/connection.c b/Modules/_sqlite/connection.c
new file mode 100644
index 0000000..e53f0b5
--- /dev/null
+++ b/Modules/_sqlite/connection.c
@@ -0,0 +1,922 @@
+/* connection.c - the connection 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 "cache.h"
+#include "module.h"
+#include "connection.h"
+#include "statement.h"
+#include "cursor.h"
+#include "prepare_protocol.h"
+#include "util.h"
+#include "pythread.h"
+
+static int connection_set_isolation_level(Connection* self, PyObject* isolation_level);
+
+int connection_init(Connection* self, PyObject* args, PyObject* kwargs)
+{
+ static char *kwlist[] = {"database", "timeout", "detect_types", "isolation_level", "check_same_thread", "factory", "cached_statements", NULL, NULL};
+
+ char* database;
+ int detect_types = 0;
+ PyObject* isolation_level = NULL;
+ PyObject* factory = NULL;
+ int check_same_thread = 1;
+ int cached_statements = 100;
+ double timeout = 5.0;
+ int rc;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|diOiOi", kwlist,
+ &database, &timeout, &detect_types, &isolation_level, &check_same_thread, &factory, &cached_statements))
+ {
+ return -1;
+ }
+
+ self->begin_statement = NULL;
+
+ self->statement_cache = NULL;
+
+ Py_INCREF(Py_None);
+ self->row_factory = Py_None;
+
+ Py_INCREF(&PyUnicode_Type);
+ self->text_factory = (PyObject*)&PyUnicode_Type;
+
+ Py_BEGIN_ALLOW_THREADS
+ rc = sqlite3_open(database, &self->db);
+ Py_END_ALLOW_THREADS
+
+ if (rc != SQLITE_OK) {
+ _seterror(self->db);
+ return -1;
+ }
+
+ if (!isolation_level) {
+ isolation_level = PyString_FromString("");
+ } else {
+ Py_INCREF(isolation_level);
+ }
+ self->isolation_level = NULL;
+ connection_set_isolation_level(self, isolation_level);
+ Py_DECREF(isolation_level);
+
+ self->statement_cache = (Cache*)PyObject_CallFunction((PyObject*)&CacheType, "Oi", self, cached_statements);
+ if (PyErr_Occurred()) {
+ return -1;
+ }
+
+ /* By default, the Cache class INCREFs the factory in its initializer, and
+ * decrefs it in its deallocator method. Since this would create a circular
+ * reference here, we're breaking it by decrementing self, and telling the
+ * cache class to not decref the factory (self) in its deallocator.
+ */
+ self->statement_cache->decref_factory = 0;
+ Py_DECREF(self);
+
+ self->inTransaction = 0;
+ self->detect_types = detect_types;
+ self->timeout = timeout;
+ (void)sqlite3_busy_timeout(self->db, (int)(timeout*1000));
+
+ self->thread_ident = PyThread_get_thread_ident();
+ self->check_same_thread = check_same_thread;
+
+ self->function_pinboard = PyDict_New();
+
+ self->Warning = Warning;
+ self->Error = Error;
+ self->InterfaceError = InterfaceError;
+ self->DatabaseError = DatabaseError;
+ self->DataError = DataError;
+ self->OperationalError = OperationalError;
+ self->IntegrityError = IntegrityError;
+ self->InternalError = InternalError;
+ self->ProgrammingError = ProgrammingError;
+ self->NotSupportedError = NotSupportedError;
+
+ return 0;
+}
+
+void flush_statement_cache(Connection* self)
+{
+ Node* node;
+ Statement* statement;
+
+ node = self->statement_cache->first;
+
+ while (node) {
+ statement = (Statement*)(node->data);
+ (void)statement_finalize(statement);
+ node = node->next;
+ }
+
+ Py_DECREF(self->statement_cache);
+ self->statement_cache = (Cache*)PyObject_CallFunction((PyObject*)&CacheType, "O", self);
+ Py_DECREF(self);
+ self->statement_cache->decref_factory = 0;
+}
+
+void reset_all_statements(Connection* self)
+{
+ Node* node;
+ Statement* statement;
+
+ node = self->statement_cache->first;
+
+ while (node) {
+ statement = (Statement*)(node->data);
+ (void)statement_reset(statement);
+ node = node->next;
+ }
+}
+
+void connection_dealloc(Connection* self)
+{
+ Py_XDECREF(self->statement_cache);
+
+ /* Clean up if user has not called .close() explicitly. */
+ if (self->db) {
+ Py_BEGIN_ALLOW_THREADS
+ sqlite3_close(self->db);
+ Py_END_ALLOW_THREADS
+ }
+
+ if (self->begin_statement) {
+ PyMem_Free(self->begin_statement);
+ }
+ Py_XDECREF(self->isolation_level);
+ Py_XDECREF(self->function_pinboard);
+ Py_XDECREF(self->row_factory);
+ Py_XDECREF(self->text_factory);
+
+ self->ob_type->tp_free((PyObject*)self);
+}
+
+PyObject* connection_cursor(Connection* self, PyObject* args, PyObject* kwargs)
+{
+ static char *kwlist[] = {"factory", NULL, NULL};
+ PyObject* factory = NULL;
+ PyObject* cursor;
+
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|O", kwlist,
+ &factory)) {
+ return NULL;
+ }
+
+ if (!check_thread(self) || !check_connection(self)) {
+ return NULL;
+ }
+
+ if (factory == NULL) {
+ factory = (PyObject*)&CursorType;
+ }
+
+ cursor = PyObject_CallFunction(factory, "O", self);
+
+ if (cursor && self->row_factory != Py_None) {
+ Py_XDECREF(((Cursor*)cursor)->row_factory);
+ Py_INCREF(self->row_factory);
+ ((Cursor*)cursor)->row_factory = self->row_factory;
+ }
+
+ return cursor;
+}
+
+PyObject* connection_close(Connection* self, PyObject* args)
+{
+ int rc;
+
+ if (!check_thread(self)) {
+ return NULL;
+ }
+
+ flush_statement_cache(self);
+
+ if (self->db) {
+ Py_BEGIN_ALLOW_THREADS
+ rc = sqlite3_close(self->db);
+ Py_END_ALLOW_THREADS
+
+ if (rc != SQLITE_OK) {
+ _seterror(self->db);
+ return NULL;
+ } else {
+ self->db = NULL;
+ }
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+/*
+ * Checks if a connection object is usable (i. e. not closed).
+ *
+ * 0 => error; 1 => ok
+ */
+int check_connection(Connection* con)
+{
+ if (!con->db) {
+ PyErr_SetString(ProgrammingError, "Cannot operate on a closed database.");
+ return 0;
+ } else {
+ return 1;
+ }
+}
+
+PyObject* _connection_begin(Connection* self)
+{
+ int rc;
+ const char* tail;
+ sqlite3_stmt* statement;
+
+ Py_BEGIN_ALLOW_THREADS
+ rc = sqlite3_prepare(self->db, self->begin_statement, -1, &statement, &tail);
+ Py_END_ALLOW_THREADS
+
+ if (rc != SQLITE_OK) {
+ _seterror(self->db);
+ goto error;
+ }
+
+ rc = _sqlite_step_with_busyhandler(statement, self);
+ if (rc == SQLITE_DONE) {
+ self->inTransaction = 1;
+ } else {
+ _seterror(self->db);
+ }
+
+ Py_BEGIN_ALLOW_THREADS
+ rc = sqlite3_finalize(statement);
+ Py_END_ALLOW_THREADS
+
+ if (rc != SQLITE_OK && !PyErr_Occurred()) {
+ _seterror(self->db);
+ }
+
+error:
+ if (PyErr_Occurred()) {
+ return NULL;
+ } else {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+}
+
+PyObject* connection_commit(Connection* self, PyObject* args)
+{
+ int rc;
+ const char* tail;
+ sqlite3_stmt* statement;
+
+ if (!check_thread(self) || !check_connection(self)) {
+ return NULL;
+ }
+
+ if (self->inTransaction) {
+ Py_BEGIN_ALLOW_THREADS
+ rc = sqlite3_prepare(self->db, "COMMIT", -1, &statement, &tail);
+ Py_END_ALLOW_THREADS
+ if (rc != SQLITE_OK) {
+ _seterror(self->db);
+ goto error;
+ }
+
+ rc = _sqlite_step_with_busyhandler(statement, self);
+ if (rc == SQLITE_DONE) {
+ self->inTransaction = 0;
+ } else {
+ _seterror(self->db);
+ }
+
+ Py_BEGIN_ALLOW_THREADS
+ rc = sqlite3_finalize(statement);
+ Py_END_ALLOW_THREADS
+ if (rc != SQLITE_OK && !PyErr_Occurred()) {
+ _seterror(self->db);
+ }
+
+ }
+
+error:
+ if (PyErr_Occurred()) {
+ return NULL;
+ } else {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+}
+
+PyObject* connection_rollback(Connection* self, PyObject* args)
+{
+ int rc;
+ const char* tail;
+ sqlite3_stmt* statement;
+
+ if (!check_thread(self) || !check_connection(self)) {
+ return NULL;
+ }
+
+ if (self->inTransaction) {
+ reset_all_statements(self);
+
+ Py_BEGIN_ALLOW_THREADS
+ rc = sqlite3_prepare(self->db, "ROLLBACK", -1, &statement, &tail);
+ Py_END_ALLOW_THREADS
+ if (rc != SQLITE_OK) {
+ _seterror(self->db);
+ goto error;
+ }
+
+ rc = _sqlite_step_with_busyhandler(statement, self);
+ if (rc == SQLITE_DONE) {
+ self->inTransaction = 0;
+ } else {
+ _seterror(self->db);
+ }
+
+ Py_BEGIN_ALLOW_THREADS
+ rc = sqlite3_finalize(statement);
+ Py_END_ALLOW_THREADS
+ if (rc != SQLITE_OK && !PyErr_Occurred()) {
+ _seterror(self->db);
+ }
+
+ }
+
+error:
+ if (PyErr_Occurred()) {
+ return NULL;
+ } else {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+}
+
+void _set_result(sqlite3_context* context, PyObject* py_val)
+{
+ long longval;
+ const char* buffer;
+ int buflen;
+ PyObject* stringval;
+
+ if (PyErr_Occurred()) {
+ /* Errors in callbacks are ignored, and we return NULL */
+ PyErr_Clear();
+ sqlite3_result_null(context);
+ } else if (py_val == Py_None) {
+ sqlite3_result_null(context);
+ } else if (PyInt_Check(py_val)) {
+ longval = PyInt_AsLong(py_val);
+ /* TODO: investigate what to do with range overflows - long vs. long long */
+ sqlite3_result_int64(context, (PY_LONG_LONG)longval);
+ } else if (PyFloat_Check(py_val)) {
+ sqlite3_result_double(context, PyFloat_AsDouble(py_val));
+ } else if (PyBuffer_Check(py_val)) {
+ if (PyObject_AsCharBuffer(py_val, &buffer, &buflen) != 0) {
+ PyErr_SetString(PyExc_ValueError, "could not convert BLOB to buffer");
+ }
+ sqlite3_result_blob(context, buffer, buflen, SQLITE_TRANSIENT);
+ } else if (PyString_Check(py_val)) {
+ sqlite3_result_text(context, PyString_AsString(py_val), -1, SQLITE_TRANSIENT);
+ } else if (PyUnicode_Check(py_val)) {
+ stringval = PyUnicode_AsUTF8String(py_val);
+ sqlite3_result_text(context, PyString_AsString(stringval), -1, SQLITE_TRANSIENT);
+ Py_DECREF(stringval);
+ } else {
+ /* TODO: raise error */
+ }
+}
+
+PyObject* _build_py_params(sqlite3_context *context, int argc, sqlite3_value** argv)
+{
+ PyObject* args;
+ int i;
+ sqlite3_value* cur_value;
+ PyObject* cur_py_value;
+ const char* val_str;
+ PY_LONG_LONG val_int;
+ int buflen;
+ void* raw_buffer;
+
+ args = PyTuple_New(argc);
+
+ for (i = 0; i < argc; i++) {
+ cur_value = argv[i];
+ switch (sqlite3_value_type(argv[i])) {
+ case SQLITE_INTEGER:
+ val_int = sqlite3_value_int64(cur_value);
+ cur_py_value = PyInt_FromLong((long)val_int);
+ break;
+ case SQLITE_FLOAT:
+ cur_py_value = PyFloat_FromDouble(sqlite3_value_double(cur_value));
+ break;
+ case SQLITE_TEXT:
+ val_str = (const char*)sqlite3_value_text(cur_value);
+ cur_py_value = PyUnicode_DecodeUTF8(val_str, strlen(val_str), NULL);
+ /* TODO: have a way to show errors here */
+ if (!cur_py_value) {
+ Py_INCREF(Py_None);
+ cur_py_value = Py_None;
+ }
+ break;
+ case SQLITE_BLOB:
+ buflen = sqlite3_value_bytes(cur_value);
+ cur_py_value = PyBuffer_New(buflen);
+ if (!cur_py_value) {
+ /* TODO: error */
+ }
+ if (PyObject_AsWriteBuffer(cur_py_value, &raw_buffer, &buflen)) {
+ /* TODO: error */
+ }
+ memcpy(raw_buffer, sqlite3_value_blob(cur_value), buflen);
+ break;
+ case SQLITE_NULL:
+ default:
+ Py_INCREF(Py_None);
+ cur_py_value = Py_None;
+ }
+ PyTuple_SetItem(args, i, cur_py_value);
+
+ }
+
+ return args;
+}
+
+void _func_callback(sqlite3_context* context, int argc, sqlite3_value** argv)
+{
+ PyObject* args;
+ PyObject* py_func;
+ PyObject* py_retval;
+
+
+ PyGILState_STATE threadstate;
+
+ threadstate = PyGILState_Ensure();
+
+ py_func = (PyObject*)sqlite3_user_data(context);
+
+ args = _build_py_params(context, argc, argv);
+
+ py_retval = PyObject_CallObject(py_func, args);
+ Py_DECREF(args);
+
+ _set_result(context, py_retval);
+ Py_XDECREF(py_retval);
+
+ PyGILState_Release(threadstate);
+}
+
+static void _step_callback(sqlite3_context *context, int argc, sqlite3_value** params)
+{
+ PyObject* args;
+ PyObject* function_result;
+ PyObject* aggregate_class;
+ PyObject** aggregate_instance;
+ PyObject* stepmethod;
+
+ PyGILState_STATE threadstate;
+
+ threadstate = PyGILState_Ensure();
+
+ aggregate_class = (PyObject*)sqlite3_user_data(context);
+
+ aggregate_instance = (PyObject**)sqlite3_aggregate_context(context, sizeof(PyObject*));
+
+ if (*aggregate_instance == 0) {
+ *aggregate_instance = PyObject_CallFunction(aggregate_class, "");
+
+ if (PyErr_Occurred())
+ {
+ PyErr_Clear();
+ *aggregate_instance = 0;
+ PyGILState_Release(threadstate);
+ return;
+ }
+ }
+
+ stepmethod = PyObject_GetAttrString(*aggregate_instance, "step");
+ if (!stepmethod)
+ {
+ PyGILState_Release(threadstate);
+ return;
+ }
+
+ args = _build_py_params(context, argc, params);
+
+ function_result = PyObject_CallObject(stepmethod, args);
+ Py_DECREF(args);
+ Py_DECREF(stepmethod);
+
+ if (function_result == NULL) {
+ PyErr_Clear();
+ } else {
+ Py_DECREF(function_result);
+ }
+
+ PyGILState_Release(threadstate);
+}
+
+void _final_callback(sqlite3_context* context)
+{
+ PyObject* args;
+ PyObject* function_result;
+ PyObject** aggregate_instance;
+ PyObject* aggregate_class;
+ PyObject* finalizemethod;
+
+ PyGILState_STATE threadstate;
+
+ threadstate = PyGILState_Ensure();
+
+ aggregate_class = (PyObject*)sqlite3_user_data(context);
+
+ aggregate_instance = (PyObject**)sqlite3_aggregate_context(context, sizeof(PyObject*));
+ if (!*aggregate_instance) {
+ /* this branch is executed if there was an exception in the aggregate's
+ * __init__ */
+
+ PyGILState_Release(threadstate);
+ return;
+ }
+
+ finalizemethod = PyObject_GetAttrString(*aggregate_instance, "finalize");
+
+ if (!finalizemethod) {
+ /*
+ PyErr_SetString(ProgrammingError, "finalize method missing");
+ goto error;
+ */
+ Py_INCREF(Py_None);
+ function_result = Py_None;
+ } else {
+ args = PyTuple_New(0);
+ function_result = PyObject_CallObject(finalizemethod, args);
+ Py_DECREF(args);
+ Py_DECREF(finalizemethod);
+ }
+
+ _set_result(context, function_result);
+ Py_XDECREF(*aggregate_instance);
+ Py_XDECREF(function_result);
+
+ PyGILState_Release(threadstate);
+}
+
+
+PyObject* connection_create_function(Connection* self, PyObject* args, PyObject* kwargs)
+{
+ static char *kwlist[] = {"name", "narg", "func", NULL, NULL};
+
+ PyObject* func;
+ char* name;
+ int narg;
+ int rc;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "siO", kwlist,
+ &name, &narg, &func))
+ {
+ return NULL;
+ }
+
+ rc = sqlite3_create_function(self->db, name, narg, SQLITE_UTF8, (void*)func, _func_callback, NULL, NULL);
+
+ PyDict_SetItem(self->function_pinboard, func, Py_None);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+PyObject* connection_create_aggregate(Connection* self, PyObject* args, PyObject* kwargs)
+{
+ PyObject* aggregate_class;
+
+ int n_arg;
+ char* name;
+ static char *kwlist[] = { "name", "n_arg", "aggregate_class", NULL };
+ int rc;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "siO:create_aggregate",
+ kwlist, &name, &n_arg, &aggregate_class)) {
+ return NULL;
+ }
+
+ rc = sqlite3_create_function(self->db, name, n_arg, SQLITE_UTF8, (void*)aggregate_class, 0, &_step_callback, &_final_callback);
+ if (rc != SQLITE_OK) {
+ _seterror(self->db);
+ return NULL;
+ } else {
+ PyDict_SetItem(self->function_pinboard, aggregate_class, Py_None);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+}
+
+int check_thread(Connection* self)
+{
+ if (self->check_same_thread) {
+ if (PyThread_get_thread_ident() != self->thread_ident) {
+ PyErr_Format(ProgrammingError,
+ "SQLite objects created in a thread can only be used in that same thread."
+ "The object was created in thread id %ld and this is thread id %ld",
+ self->thread_ident, PyThread_get_thread_ident());
+ return 0;
+ }
+
+ }
+
+ return 1;
+}
+
+static PyObject* connection_get_isolation_level(Connection* self, void* unused)
+{
+ Py_INCREF(self->isolation_level);
+ return self->isolation_level;
+}
+
+static int connection_set_isolation_level(Connection* self, PyObject* isolation_level)
+{
+ PyObject* empty;
+ PyObject* res;
+ PyObject* begin_statement;
+
+ Py_XDECREF(self->isolation_level);
+
+ if (isolation_level == Py_None) {
+ Py_INCREF(Py_None);
+ self->begin_statement = NULL;
+ self->isolation_level = Py_None;
+
+ empty = PyTuple_New(0);
+ res = connection_commit(self, empty);
+ Py_DECREF(empty);
+ Py_DECREF(res);
+
+ self->inTransaction = 0;
+ } else {
+ Py_INCREF(isolation_level);
+ self->isolation_level = isolation_level;
+
+ begin_statement = PyString_FromString("BEGIN ");
+ if (!begin_statement) {
+ return -1;
+ }
+ PyString_Concat(&begin_statement, isolation_level);
+ if (!begin_statement) {
+ return -1;
+ }
+
+ self->begin_statement = PyMem_Malloc(PyString_Size(begin_statement) + 2);
+ if (!self->begin_statement) {
+ return -1;
+ }
+
+ strcpy(self->begin_statement, PyString_AsString(begin_statement));
+ Py_DECREF(begin_statement);
+ }
+
+ return 0;
+}
+
+PyObject* connection_call(Connection* self, PyObject* args, PyObject* kwargs)
+{
+ PyObject* sql;
+ Statement* statement;
+ int rc;
+
+ if (!PyArg_ParseTuple(args, "O", &sql)) {
+ return NULL;
+ }
+
+ statement = PyObject_New(Statement, &StatementType);
+ if (!statement) {
+ return NULL;
+ }
+
+ rc = statement_create(statement, self, sql);
+
+ if (rc != SQLITE_OK) {
+ if (rc == PYSQLITE_TOO_MUCH_SQL) {
+ PyErr_SetString(Warning, "You can only execute one statement at a time.");
+ } else if (rc == PYSQLITE_SQL_WRONG_TYPE) {
+ PyErr_SetString(Warning, "SQL is of wrong type. Must be string or unicode.");
+ } else {
+ _seterror(self->db);
+ }
+
+ Py_DECREF(statement);
+ statement = 0;
+ }
+
+ return (PyObject*)statement;
+}
+
+PyObject* connection_execute(Connection* self, PyObject* args, PyObject* kwargs)
+{
+ PyObject* cursor = 0;
+ PyObject* result = 0;
+ PyObject* method = 0;
+
+ cursor = PyObject_CallMethod((PyObject*)self, "cursor", "");
+ if (!cursor) {
+ goto error;
+ }
+
+ method = PyObject_GetAttrString(cursor, "execute");
+ if (!method) {
+ Py_DECREF(cursor);
+ cursor = 0;
+ goto error;
+ }
+
+ result = PyObject_CallObject(method, args);
+ if (!result) {
+ Py_DECREF(cursor);
+ cursor = 0;
+ }
+
+error:
+ Py_XDECREF(result);
+ Py_XDECREF(method);
+
+ return cursor;
+}
+
+PyObject* connection_executemany(Connection* self, PyObject* args, PyObject* kwargs)
+{
+ PyObject* cursor = 0;
+ PyObject* result = 0;
+ PyObject* method = 0;
+
+ cursor = PyObject_CallMethod((PyObject*)self, "cursor", "");
+ if (!cursor) {
+ goto error;
+ }
+
+ method = PyObject_GetAttrString(cursor, "executemany");
+ if (!method) {
+ Py_DECREF(cursor);
+ cursor = 0;
+ goto error;
+ }
+
+ result = PyObject_CallObject(method, args);
+ if (!result) {
+ Py_DECREF(cursor);
+ cursor = 0;
+ }
+
+error:
+ Py_XDECREF(result);
+ Py_XDECREF(method);
+
+ return cursor;
+}
+
+PyObject* connection_executescript(Connection* self, PyObject* args, PyObject* kwargs)
+{
+ PyObject* cursor = 0;
+ PyObject* result = 0;
+ PyObject* method = 0;
+
+ cursor = PyObject_CallMethod((PyObject*)self, "cursor", "");
+ if (!cursor) {
+ goto error;
+ }
+
+ method = PyObject_GetAttrString(cursor, "executescript");
+ if (!method) {
+ Py_DECREF(cursor);
+ cursor = 0;
+ goto error;
+ }
+
+ result = PyObject_CallObject(method, args);
+ if (!result) {
+ Py_DECREF(cursor);
+ cursor = 0;
+ }
+
+error:
+ Py_XDECREF(result);
+ Py_XDECREF(method);
+
+ return cursor;
+}
+
+static char connection_doc[] =
+PyDoc_STR("<missing docstring>");
+
+static PyGetSetDef connection_getset[] = {
+ {"isolation_level", (getter)connection_get_isolation_level, (setter)connection_set_isolation_level},
+ {NULL}
+};
+
+static PyMethodDef connection_methods[] = {
+ {"cursor", (PyCFunction)connection_cursor, METH_VARARGS|METH_KEYWORDS,
+ PyDoc_STR("Return a cursor for the connection.")},
+ {"close", (PyCFunction)connection_close, METH_NOARGS,
+ PyDoc_STR("Closes the connection.")},
+ {"commit", (PyCFunction)connection_commit, METH_NOARGS,
+ PyDoc_STR("Commit the current transaction.")},
+ {"rollback", (PyCFunction)connection_rollback, METH_NOARGS,
+ PyDoc_STR("Roll back the current transaction.")},
+ {"create_function", (PyCFunction)connection_create_function, METH_VARARGS|METH_KEYWORDS,
+ PyDoc_STR("Creates a new function. Non-standard.")},
+ {"create_aggregate", (PyCFunction)connection_create_aggregate, METH_VARARGS|METH_KEYWORDS,
+ PyDoc_STR("Creates a new aggregate. Non-standard.")},
+ {"execute", (PyCFunction)connection_execute, METH_VARARGS,
+ PyDoc_STR("Executes a SQL statement. Non-standard.")},
+ {"executemany", (PyCFunction)connection_executemany, METH_VARARGS,
+ PyDoc_STR("Repeatedly executes a SQL statement. Non-standard.")},
+ {"executescript", (PyCFunction)connection_executescript, METH_VARARGS,
+ PyDoc_STR("Executes a multiple SQL statements at once. Non-standard.")},
+ {NULL, NULL}
+};
+
+static struct PyMemberDef connection_members[] =
+{
+ {"Warning", T_OBJECT, offsetof(Connection, Warning), RO},
+ {"Error", T_OBJECT, offsetof(Connection, Error), RO},
+ {"InterfaceError", T_OBJECT, offsetof(Connection, InterfaceError), RO},
+ {"DatabaseError", T_OBJECT, offsetof(Connection, DatabaseError), RO},
+ {"DataError", T_OBJECT, offsetof(Connection, DataError), RO},
+ {"OperationalError", T_OBJECT, offsetof(Connection, OperationalError), RO},
+ {"IntegrityError", T_OBJECT, offsetof(Connection, IntegrityError), RO},
+ {"InternalError", T_OBJECT, offsetof(Connection, InternalError), RO},
+ {"ProgrammingError", T_OBJECT, offsetof(Connection, ProgrammingError), RO},
+ {"NotSupportedError", T_OBJECT, offsetof(Connection, NotSupportedError), RO},
+ {"row_factory", T_OBJECT, offsetof(Connection, row_factory)},
+ {"text_factory", T_OBJECT, offsetof(Connection, text_factory)},
+ {NULL}
+};
+
+PyTypeObject ConnectionType = {
+ PyObject_HEAD_INIT(NULL)
+ 0, /* ob_size */
+ "pysqlite2.dbapi2.Connection", /* tp_name */
+ sizeof(Connection), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)connection_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 */
+ (ternaryfunc)connection_call, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /* tp_flags */
+ connection_doc, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ connection_methods, /* tp_methods */
+ connection_members, /* tp_members */
+ connection_getset, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)connection_init, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+ 0 /* tp_free */
+};
+
+extern int connection_setup_types(void)
+{
+ ConnectionType.tp_new = PyType_GenericNew;
+ return PyType_Ready(&ConnectionType);
+}
diff --git a/Modules/_sqlite/connection.h b/Modules/_sqlite/connection.h
new file mode 100644
index 0000000..ef03bc4
--- /dev/null
+++ b/Modules/_sqlite/connection.h
@@ -0,0 +1,103 @@
+/* connection.h - definitions for the connection type
+ *
+ * Copyright (C) 2004-2005 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.
+ */
+
+#ifndef PYSQLITE_CONNECTION_H
+#define PYSQLITE_CONNECTION_H
+#include "Python.h"
+#include "pythread.h"
+#include "structmember.h"
+
+#include "cache.h"
+#include "module.h"
+
+#include "sqlite3.h"
+
+typedef struct
+{
+ PyObject_HEAD
+ sqlite3* db;
+
+ int inTransaction;
+ int detect_types;
+
+ /* the timeout value in seconds for database locks */
+ double timeout;
+
+ /* for internal use in the timeout handler: when did the timeout handler
+ * first get called with count=0? */
+ double timeout_started;
+
+ /* None for autocommit, otherwise a PyString with the isolation level */
+ PyObject* isolation_level;
+
+ /* NULL for autocommit, otherwise a string with the BEGIN statment; will be
+ * freed in connection destructor */
+ char* begin_statement;
+
+ int check_same_thread;
+ long thread_ident;
+
+ Cache* statement_cache;
+
+ PyObject* row_factory;
+
+ PyObject* text_factory;
+
+ /* remember references to functions/classes used in
+ * create_function/create/aggregate, use these as dictionary keys, so we
+ * can keep the total system refcount constant by clearing that dictionary
+ * in connection_dealloc */
+ PyObject* function_pinboard;
+
+ /* Exception objects */
+ PyObject* Warning;
+ PyObject* Error;
+ PyObject* InterfaceError;
+ PyObject* DatabaseError;
+ PyObject* DataError;
+ PyObject* OperationalError;
+ PyObject* IntegrityError;
+ PyObject* InternalError;
+ PyObject* ProgrammingError;
+ PyObject* NotSupportedError;
+} Connection;
+
+extern PyTypeObject ConnectionType;
+
+PyObject* connection_alloc(PyTypeObject* type, int aware);
+void connection_dealloc(Connection* self);
+PyObject* connection_cursor(Connection* self, PyObject* args, PyObject* kwargs);
+PyObject* connection_close(Connection* self, PyObject* args);
+PyObject* _connection_begin(Connection* self);
+PyObject* connection_begin(Connection* self, PyObject* args);
+PyObject* connection_commit(Connection* self, PyObject* args);
+PyObject* connection_rollback(Connection* self, PyObject* args);
+PyObject* connection_new(PyTypeObject* type, PyObject* args, PyObject* kw);
+int connection_init(Connection* self, PyObject* args, PyObject* kwargs);
+
+int check_thread(Connection* self);
+int check_connection(Connection* con);
+
+int connection_setup_types(void);
+
+#endif
diff --git a/Modules/_sqlite/converters.c b/Modules/_sqlite/converters.c
new file mode 100644
index 0000000..018063a
--- /dev/null
+++ b/Modules/_sqlite/converters.c
@@ -0,0 +1,40 @@
+/* converters.c - default converters
+ *
+ * Copyright (C) 2005 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 "util.h"
+#include "module.h"
+#include "adapters.h"
+
+/* dummy, will be implemented in a later version */
+
+PyObject* convert_date(PyObject* self, PyObject* args, PyObject* kwargs)
+{
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+PyObject* convert_timestamp(PyObject* self, PyObject* args, PyObject* kwargs)
+{
+ Py_INCREF(Py_None);
+ return Py_None;
+}
diff --git a/Modules/_sqlite/converters.h b/Modules/_sqlite/converters.h
new file mode 100644
index 0000000..df3768a
--- /dev/null
+++ b/Modules/_sqlite/converters.h
@@ -0,0 +1,33 @@
+/* converters.h - default converters
+ *
+ * Copyright (C) 2005 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.
+ */
+
+#ifndef PYSQLITE_CONVERTERS_H
+#define PYSQLITE_CONVERTERS_H
+#include "Python.h"
+#include "pythread.h"
+#include "sqlite3.h"
+
+PyObject* convert_date(PyObject* self, PyObject* args, PyObject* kwargs);
+PyObject* convert_timestamp(PyObject* self, PyObject* args, PyObject* kwargs);
+
+#endif
diff --git a/Modules/_sqlite/cursor.c b/Modules/_sqlite/cursor.c
new file mode 100644
index 0000000..c6ab25a
--- /dev/null
+++ b/Modules/_sqlite/cursor.c
@@ -0,0 +1,1067 @@
+/* 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 "microprotocols.h"
+#include "prepare_protocol.h"
+
+/* used to decide wether to call PyInt_FromLong or PyLong_FromLongLong */
+#define INT32_MIN (-2147483647 - 1)
+#define INT32_MAX 2147483647
+
+PyObject* cursor_iternext(Cursor *self);
+
+static 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 cursor_init(Cursor* self, PyObject* args, PyObject* kwargs)
+{
+ Connection* connection;
+
+ if (!PyArg_ParseTuple(args, "O!", &ConnectionType, &connection))
+ {
+ return -1;
+ }
+
+ Py_INCREF(connection);
+ self->connection = connection;
+ self->statement = NULL;
+ self->next_row = NULL;
+
+ self->row_cast_map = PyList_New(0);
+
+ Py_INCREF(Py_None);
+ self->description = Py_None;
+
+ Py_INCREF(Py_None);
+ self->lastrowid= Py_None;
+
+ self->arraysize = 1;
+
+ self->rowcount = PyInt_FromLong(-1L);
+
+ Py_INCREF(Py_None);
+ self->row_factory = Py_None;
+
+ if (!check_thread(self->connection)) {
+ return -1;
+ }
+
+ return 0;
+}
+
+void cursor_dealloc(Cursor* self)
+{
+ int rc;
+
+ /* Reset the statement if the user has not closed the cursor */
+ if (self->statement) {
+ rc = 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);
+}
+
+void build_row_cast_map(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;
+ }
+
+ Py_DECREF(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);
+
+ 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);
+ converter = PyDict_GetItem(converters, 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);
+ break;
+ }
+ }
+
+ converter = PyDict_GetItem(converters, py_decltype);
+ Py_DECREF(py_decltype);
+ }
+ }
+
+ if (converter) {
+ PyList_Append(self->row_cast_map, converter);
+ } else {
+ PyList_Append(self->row_cast_map, Py_None);
+ }
+ }
+}
+
+int _bind_parameter(Cursor* self, int pos, PyObject* parameter)
+{
+ int rc = SQLITE_OK;
+ long longval;
+#ifdef HAVE_LONG_LONG
+ PY_LONG_LONG longlongval;
+#endif
+ const char* buffer;
+ char* string;
+ int buflen;
+ PyObject* stringval;
+
+ if (parameter == Py_None) {
+ rc = sqlite3_bind_null(self->statement->st, pos);
+ } else if (PyInt_Check(parameter)) {
+ longval = PyInt_AsLong(parameter);
+ rc = sqlite3_bind_int64(self->statement->st, pos, (sqlite_int64)longval);
+#ifdef HAVE_LONG_LONG
+ } else if (PyLong_Check(parameter)) {
+ longlongval = PyLong_AsLongLong(parameter);
+ /* in the overflow error case, longlongval is -1, and an exception is set */
+ rc = sqlite3_bind_int64(self->statement->st, pos, (sqlite_int64)longlongval);
+#endif
+ } else if (PyFloat_Check(parameter)) {
+ rc = sqlite3_bind_double(self->statement->st, pos, PyFloat_AsDouble(parameter));
+ } else if (PyBuffer_Check(parameter)) {
+ if (PyObject_AsCharBuffer(parameter, &buffer, &buflen) == 0) {
+ rc = sqlite3_bind_blob(self->statement->st, pos, buffer, buflen, SQLITE_TRANSIENT);
+ } else {
+ PyErr_SetString(PyExc_ValueError, "could not convert BLOB to buffer");
+ rc = -1;
+ }
+ } else if PyString_Check(parameter) {
+ string = PyString_AsString(parameter);
+ rc = sqlite3_bind_text(self->statement->st, pos, string, -1, SQLITE_TRANSIENT);
+ } else if PyUnicode_Check(parameter) {
+ stringval = PyUnicode_AsUTF8String(parameter);
+ string = PyString_AsString(stringval);
+ rc = sqlite3_bind_text(self->statement->st, pos, string, -1, SQLITE_TRANSIENT);
+ Py_DECREF(stringval);
+ } else {
+ rc = -1;
+ }
+
+ return rc;
+}
+
+PyObject* _build_column_name(const char* colname)
+{
+ const char* pos;
+
+ for (pos = colname;; pos++) {
+ if (*pos == 0 || *pos == ' ') {
+ return PyString_FromStringAndSize(colname, pos - colname);
+ }
+ }
+}
+
+PyObject* 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* _fetch_one_row(Cursor* self)
+{
+ int i, numcols;
+ PyObject* row;
+ PyObject* item = NULL;
+ int coltype;
+ PY_LONG_LONG intval;
+ PyObject* converter;
+ PyObject* converted;
+ int nbytes;
+ PyObject* buffer;
+ void* raw_buffer;
+ const char* val_str;
+ char buf[200];
+
+ Py_BEGIN_ALLOW_THREADS
+ numcols = sqlite3_data_count(self->statement->st);
+ Py_END_ALLOW_THREADS
+
+ row = PyTuple_New(numcols);
+
+ 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) {
+ val_str = (const char*)sqlite3_column_text(self->statement->st, i);
+ if (!val_str) {
+ Py_INCREF(Py_None);
+ converted = Py_None;
+ } else {
+ item = PyString_FromString(val_str);
+ converted = PyObject_CallFunction(converter, "O", item);
+ if (!converted) {
+ /* TODO: have a way to log these errors */
+ Py_INCREF(Py_None);
+ converted = Py_None;
+ PyErr_Clear();
+ }
+ Py_DECREF(item);
+ }
+ } 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 == OptimizedUnicode)) {
+
+ converted = unicode_from_string(val_str,
+ self->connection->text_factory == OptimizedUnicode ? 1 : 0);
+
+ if (!converted) {
+ PyOS_snprintf(buf, sizeof(buf) - 1, "Could not decode to UTF-8 column %s with text %s",
+ sqlite3_column_name(self->statement->st, i), val_str);
+ PyErr_SetString(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;
+ }
+ }
+
+ PyTuple_SetItem(row, i, converted);
+ }
+
+ if (PyErr_Occurred()) {
+ Py_DECREF(row);
+ row = NULL;
+ }
+
+ return row;
+}
+
+PyObject* _query_execute(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 num_params;
+ int i;
+ int rc;
+ PyObject* func_args;
+ PyObject* result;
+ int numcols;
+ PY_LONG_LONG lastrowid;
+ int statement_type;
+ PyObject* descriptor;
+ PyObject* current_param;
+ PyObject* adapted;
+ PyObject* second_argument = NULL;
+ int num_params_needed;
+ const char* binding_name;
+ long rowcount = 0;
+
+ if (!check_thread(self->connection) || !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 (PyErr_Occurred())
+ {
+ 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);
+ } else {
+ Py_INCREF(second_argument);
+ }
+ PyList_Append(parameters_list, second_argument);
+ Py_DECREF(second_argument);
+
+ parameters_iter = PyObject_GetIter(parameters_list);
+ }
+
+ if (self->statement != NULL) {
+ /* There is an active statement */
+ rc = 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);
+
+ 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 = _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) {
+ func_args = PyTuple_New(0);
+ result = connection_commit(self->connection, func_args);
+ Py_DECREF(func_args);
+ if (!result) {
+ goto error;
+ }
+ Py_DECREF(result);
+ }
+ break;
+ case STATEMENT_SELECT:
+ if (multiple) {
+ PyErr_SetString(ProgrammingError,
+ "You cannot execute SELECT statements in executemany().");
+ goto error;
+ }
+ }
+ }
+
+ func_args = PyTuple_New(1);
+ Py_INCREF(operation);
+ PyTuple_SetItem(func_args, 0, operation);
+
+ if (self->statement) {
+ (void)statement_reset(self->statement);
+ Py_DECREF(self->statement);
+ }
+
+ self->statement = (Statement*)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(Statement, &StatementType);
+ rc = statement_create(self->statement, self->connection, operation);
+ if (rc != SQLITE_OK) {
+ self->statement = 0;
+ goto error;
+ }
+ }
+
+ statement_reset(self->statement);
+ statement_mark_dirty(self->statement);
+
+ Py_BEGIN_ALLOW_THREADS
+ num_params_needed = sqlite3_bind_parameter_count(self->statement->st);
+ Py_END_ALLOW_THREADS
+
+ while (1) {
+ parameters = PyIter_Next(parameters_iter);
+ if (!parameters) {
+ break;
+ }
+
+ statement_mark_dirty(self->statement);
+
+ if (PyDict_Check(parameters)) {
+ /* parameters passed as dictionary */
+ for (i = 1; i <= num_params_needed; i++) {
+ Py_BEGIN_ALLOW_THREADS
+ binding_name = sqlite3_bind_parameter_name(self->statement->st, i);
+ Py_END_ALLOW_THREADS
+ if (!binding_name) {
+ PyErr_Format(ProgrammingError, "Binding %d has no name, but you supplied a dictionary (which has only names).", i);
+ goto error;
+ }
+
+ binding_name++; /* skip first char (the colon) */
+ current_param = PyDict_GetItemString(parameters, binding_name);
+ if (!current_param) {
+ PyErr_Format(ProgrammingError, "You did not supply a value for binding %d.", i);
+ goto error;
+ }
+
+ Py_INCREF(current_param);
+ adapted = microprotocols_adapt(current_param, (PyObject*)&SQLitePrepareProtocolType, NULL);
+ if (adapted) {
+ Py_DECREF(current_param);
+ } else {
+ PyErr_Clear();
+ adapted = current_param;
+ }
+
+ rc = _bind_parameter(self, i, adapted);
+ Py_DECREF(adapted);
+
+ if (rc != SQLITE_OK) {
+ PyErr_Format(InterfaceError, "Error binding parameter :%s - probably unsupported type.", binding_name);
+ goto error;
+ }
+ }
+ } else {
+ /* parameters passed as sequence */
+ num_params = PySequence_Length(parameters);
+ if (num_params != num_params_needed) {
+ PyErr_Format(ProgrammingError, "Incorrect number of bindings supplied. The current statement uses %d, and there are %d supplied.",
+ num_params_needed, num_params);
+ goto error;
+ }
+ for (i = 0; i < num_params; i++) {
+ current_param = PySequence_GetItem(parameters, i);
+ if (!current_param) {
+ goto error;
+ }
+ adapted = microprotocols_adapt(current_param, (PyObject*)&SQLitePrepareProtocolType, NULL);
+
+ if (adapted) {
+ Py_DECREF(current_param);
+ } else {
+ PyErr_Clear();
+ adapted = current_param;
+ }
+
+ rc = _bind_parameter(self, i + 1, adapted);
+ Py_DECREF(adapted);
+
+ if (rc != SQLITE_OK) {
+ PyErr_Format(InterfaceError, "Error binding parameter %d - probably unsupported type.", i);
+ goto error;
+ }
+ }
+ }
+
+ build_row_cast_map(self);
+
+ rc = _sqlite_step_with_busyhandler(self->statement->st, self->connection);
+ if (rc != SQLITE_DONE && rc != SQLITE_ROW) {
+ rc = statement_reset(self->statement);
+ if (rc == SQLITE_SCHEMA) {
+ rc = statement_recompile(self->statement);
+ if (rc == SQLITE_OK) {
+ rc = _sqlite_step_with_busyhandler(self->statement->st, self->connection);
+ } else {
+ _seterror(self->connection->db);
+ goto error;
+ }
+ } else {
+ _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);
+ for (i = 0; i < numcols; i++) {
+ descriptor = PyTuple_New(7);
+ PyTuple_SetItem(descriptor, 0, _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(ProgrammingError, "executemany() can only execute DML statements.");
+ goto error;
+ }
+
+ self->next_row = _fetch_one_row(self);
+ } else if (rc == SQLITE_DONE && !multiple) {
+ 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 = statement_reset(self->statement);
+ }
+ Py_XDECREF(parameters);
+ }
+
+error:
+ Py_XDECREF(operation_bytestr);
+ Py_XDECREF(parameters);
+ Py_DECREF(parameters_iter);
+ Py_XDECREF(parameters_list);
+
+ if (PyErr_Occurred()) {
+ return NULL;
+ } else {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+}
+
+PyObject* cursor_execute(Cursor* self, PyObject* args)
+{
+ return _query_execute(self, 0, args);
+}
+
+PyObject* cursor_executemany(Cursor* self, PyObject* args)
+{
+ return _query_execute(self, 1, args);
+}
+
+PyObject* cursor_executescript(Cursor* self, PyObject* args)
+{
+ PyObject* script_obj;
+ PyObject* script_str = NULL;
+ const char* script_cstr;
+ sqlite3_stmt* statement;
+ int rc;
+ PyObject* func_args;
+ PyObject* result;
+ int statement_completed = 0;
+
+ if (!PyArg_ParseTuple(args, "O", &script_obj)) {
+ return NULL;
+ }
+
+ if (!check_thread(self->connection) || !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_obj) {
+ return NULL;
+ }
+
+ script_cstr = PyString_AsString(script_str);
+ } else {
+ PyErr_SetString(PyExc_ValueError, "script argument must be unicode or string.");
+ return NULL;
+ }
+
+ /* commit first */
+ func_args = PyTuple_New(0);
+ result = connection_commit(self->connection, func_args);
+ Py_DECREF(func_args);
+ 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) {
+ _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);
+ _seterror(self->connection->db);
+ goto error;
+ }
+
+ rc = sqlite3_finalize(statement);
+ if (rc != SQLITE_OK) {
+ _seterror(self->connection->db);
+ goto error;
+ }
+ }
+
+error:
+ Py_XDECREF(script_str);
+
+ if (!statement_completed) {
+ PyErr_SetString(ProgrammingError, "you did not provide a complete SQL statement");
+ }
+
+ if (PyErr_Occurred()) {
+ return NULL;
+ } else {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+}
+
+PyObject* cursor_getiter(Cursor *self)
+{
+ Py_INCREF(self);
+ return (PyObject*)self;
+}
+
+PyObject* cursor_iternext(Cursor *self)
+{
+ PyObject* next_row_tuple;
+ PyObject* next_row;
+ int rc;
+
+ if (!check_thread(self->connection) || !check_connection(self->connection)) {
+ return NULL;
+ }
+
+ if (!self->next_row) {
+ if (self->statement) {
+ (void)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;
+ }
+
+ rc = _sqlite_step_with_busyhandler(self->statement->st, self->connection);
+ if (rc != SQLITE_DONE && rc != SQLITE_ROW) {
+ Py_DECREF(next_row);
+ _seterror(self->connection->db);
+ return NULL;
+ }
+
+ if (rc == SQLITE_ROW) {
+ self->next_row = _fetch_one_row(self);
+ }
+
+ return next_row;
+}
+
+PyObject* cursor_fetchone(Cursor* self, PyObject* args)
+{
+ PyObject* row;
+
+ row = cursor_iternext(self);
+ if (!row && !PyErr_Occurred()) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ return row;
+}
+
+PyObject* cursor_fetchmany(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);
+
+ /* just make sure we enter the loop */
+ row = (PyObject*)1;
+
+ while (row) {
+ row = 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* cursor_fetchall(Cursor* self, PyObject* args)
+{
+ PyObject* row;
+ PyObject* list;
+
+ list = PyList_New(0);
+
+ /* just make sure we enter the loop */
+ row = (PyObject*)1;
+
+ while (row) {
+ row = 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(Connection* self, PyObject* args)
+{
+ /* don't care, return None */
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+PyObject* cursor_close(Cursor* self, PyObject* args)
+{
+ if (!check_thread(self->connection) || !check_connection(self->connection)) {
+ return NULL;
+ }
+
+ if (self->statement) {
+ (void)statement_reset(self->statement);
+ Py_DECREF(self->statement);
+ self->statement = 0;
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyMethodDef cursor_methods[] = {
+ {"execute", (PyCFunction)cursor_execute, METH_VARARGS,
+ PyDoc_STR("Executes a SQL statement.")},
+ {"executemany", (PyCFunction)cursor_executemany, METH_VARARGS,
+ PyDoc_STR("Repeatedly executes a SQL statement.")},
+ {"executescript", (PyCFunction)cursor_executescript, METH_VARARGS,
+ PyDoc_STR("Executes a multiple SQL statements at once. Non-standard.")},
+ {"fetchone", (PyCFunction)cursor_fetchone, METH_NOARGS,
+ PyDoc_STR("Fetches several rows from the resultset.")},
+ {"fetchmany", (PyCFunction)cursor_fetchmany, METH_VARARGS,
+ PyDoc_STR("Fetches all rows from the resultset.")},
+ {"fetchall", (PyCFunction)cursor_fetchall, METH_NOARGS,
+ PyDoc_STR("Fetches one row from the resultset.")},
+ {"close", (PyCFunction)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(Cursor, connection), RO},
+ {"description", T_OBJECT, offsetof(Cursor, description), RO},
+ {"arraysize", T_INT, offsetof(Cursor, arraysize), 0},
+ {"lastrowid", T_OBJECT, offsetof(Cursor, lastrowid), RO},
+ {"rowcount", T_OBJECT, offsetof(Cursor, rowcount), RO},
+ {"row_factory", T_OBJECT, offsetof(Cursor, row_factory), 0},
+ {NULL}
+};
+
+PyTypeObject CursorType = {
+ PyObject_HEAD_INIT(NULL)
+ 0, /* ob_size */
+ "pysqlite2.dbapi2.Cursor", /* tp_name */
+ sizeof(Cursor), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)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_HAVE_ITER|Py_TPFLAGS_BASETYPE, /* tp_flags */
+ 0, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ (getiterfunc)cursor_getiter, /* tp_iter */
+ (iternextfunc)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)cursor_init, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+ 0 /* tp_free */
+};
+
+extern int cursor_setup_types(void)
+{
+ CursorType.tp_new = PyType_GenericNew;
+ return PyType_Ready(&CursorType);
+}
diff --git a/Modules/_sqlite/cursor.h b/Modules/_sqlite/cursor.h
new file mode 100644
index 0000000..7f56799
--- /dev/null
+++ b/Modules/_sqlite/cursor.h
@@ -0,0 +1,71 @@
+/* cursor.h - definitions for the cursor type
+ *
+ * Copyright (C) 2004-2005 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.
+ */
+
+#ifndef PYSQLITE_CURSOR_H
+#define PYSQLITE_CURSOR_H
+#include "Python.h"
+
+#include "statement.h"
+#include "connection.h"
+#include "module.h"
+
+typedef struct
+{
+ PyObject_HEAD
+ Connection* connection;
+ PyObject* description;
+ PyObject* row_cast_map;
+ int arraysize;
+ PyObject* lastrowid;
+ PyObject* rowcount;
+ PyObject* row_factory;
+ Statement* statement;
+
+ /* the next row to be returned, NULL if no next row available */
+ PyObject* next_row;
+} Cursor;
+
+typedef enum {
+ STATEMENT_INVALID, STATEMENT_INSERT, STATEMENT_DELETE,
+ STATEMENT_UPDATE, STATEMENT_REPLACE, STATEMENT_SELECT,
+ STATEMENT_OTHER
+} StatementKind;
+
+extern PyTypeObject CursorType;
+
+int cursor_init(Cursor* self, PyObject* args, PyObject* kwargs);
+void cursor_dealloc(Cursor* self);
+PyObject* cursor_execute(Cursor* self, PyObject* args);
+PyObject* cursor_executemany(Cursor* self, PyObject* args);
+PyObject* cursor_getiter(Cursor *self);
+PyObject* cursor_iternext(Cursor *self);
+PyObject* cursor_fetchone(Cursor* self, PyObject* args);
+PyObject* cursor_fetchmany(Cursor* self, PyObject* args);
+PyObject* cursor_fetchall(Cursor* self, PyObject* args);
+PyObject* pysqlite_noop(Connection* self, PyObject* args);
+PyObject* cursor_close(Cursor* self, PyObject* args);
+
+int cursor_setup_types(void);
+
+#define UNKNOWN (-1)
+#endif
diff --git a/Modules/_sqlite/microprotocols.c b/Modules/_sqlite/microprotocols.c
new file mode 100644
index 0000000..5df41a1
--- /dev/null
+++ b/Modules/_sqlite/microprotocols.c
@@ -0,0 +1,141 @@
+/* microprotocols.c - minimalist and non-validating protocols implementation
+ *
+ * Copyright (C) 2003-2004 Federico Di Gregorio <fog@debian.org>
+ *
+ * This file is part of psycopg and was adapted for pysqlite. Federico Di
+ * Gregorio gave the permission to use it within pysqlite under the following
+ * license:
+ *
+ * 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 <Python.h>
+#include <structmember.h>
+
+#include "cursor.h"
+#include "microprotocols.h"
+#include "prepare_protocol.h"
+
+
+/** the adapters registry **/
+
+PyObject *psyco_adapters;
+
+/* microprotocols_init - initialize the adapters dictionary */
+
+int
+microprotocols_init(PyObject *dict)
+{
+ /* create adapters dictionary and put it in module namespace */
+ if ((psyco_adapters = PyDict_New()) == NULL) {
+ return -1;
+ }
+
+ PyDict_SetItemString(dict, "adapters", psyco_adapters);
+
+ return 0;
+}
+
+
+/* microprotocols_add - add a reverse type-caster to the dictionary */
+
+int
+microprotocols_add(PyTypeObject *type, PyObject *proto, PyObject *cast)
+{
+ PyObject* key;
+
+ if (proto == NULL) proto = (PyObject*)&SQLitePrepareProtocolType;
+
+ /*
+ Dprintf("microprotocols_add: cast %p for (%s, ?)",
+ cast, type->tp_name);
+ */
+
+ key = Py_BuildValue("(OO)", (PyObject*)type, proto);
+ PyDict_SetItem(psyco_adapters, key, cast);
+ Py_DECREF(key);
+
+ return 0;
+}
+
+/* microprotocols_adapt - adapt an object to the built-in protocol */
+
+PyObject *
+microprotocols_adapt(PyObject *obj, PyObject *proto, PyObject *alt)
+{
+ PyObject *adapter, *key;
+
+ /* we don't check for exact type conformance as specified in PEP 246
+ because the SQLitePrepareProtocolType type is abstract and there is no
+ way to get a quotable object to be its instance */
+
+ /* look for an adapter in the registry */
+ key = Py_BuildValue("(OO)", (PyObject*)obj->ob_type, proto);
+ adapter = PyDict_GetItem(psyco_adapters, key);
+ Py_DECREF(key);
+ if (adapter) {
+ PyObject *adapted = PyObject_CallFunctionObjArgs(adapter, obj, NULL);
+ return adapted;
+ }
+
+ /* try to have the protocol adapt this object*/
+ if (PyObject_HasAttrString(proto, "__adapt__")) {
+ PyObject *adapted = PyObject_CallMethod(proto, "__adapt__", "O", obj);
+ if (adapted) {
+ if (adapted != Py_None) {
+ return adapted;
+ } else {
+ Py_DECREF(adapted);
+ }
+ }
+
+ if (PyErr_Occurred() && !PyErr_ExceptionMatches(PyExc_TypeError))
+ return NULL;
+ }
+
+ /* and finally try to have the object adapt itself */
+ if (PyObject_HasAttrString(obj, "__conform__")) {
+ PyObject *adapted = PyObject_CallMethod(obj, "__conform__","O", proto);
+ if (adapted) {
+ if (adapted != Py_None) {
+ return adapted;
+ } else {
+ Py_DECREF(adapted);
+ }
+ }
+
+ if (PyErr_Occurred() && !PyErr_ExceptionMatches(PyExc_TypeError)) {
+ return NULL;
+ }
+ }
+
+ /* else set the right exception and return NULL */
+ PyErr_SetString(ProgrammingError, "can't adapt");
+ return NULL;
+}
+
+/** module-level functions **/
+
+PyObject *
+psyco_microprotocols_adapt(Cursor *self, PyObject *args)
+{
+ PyObject *obj, *alt = NULL;
+ PyObject *proto = (PyObject*)&SQLitePrepareProtocolType;
+
+ if (!PyArg_ParseTuple(args, "O|OO", &obj, &proto, &alt)) return NULL;
+ return microprotocols_adapt(obj, proto, alt);
+}
diff --git a/Modules/_sqlite/microprotocols.h b/Modules/_sqlite/microprotocols.h
new file mode 100644
index 0000000..d2d9b65
--- /dev/null
+++ b/Modules/_sqlite/microprotocols.h
@@ -0,0 +1,59 @@
+/* microprotocols.c - definitions for minimalist and non-validating protocols
+ *
+ * Copyright (C) 2003-2004 Federico Di Gregorio <fog@debian.org>
+ *
+ * This file is part of psycopg and was adapted for pysqlite. Federico Di
+ * Gregorio gave the permission to use it within pysqlite under the following
+ * license:
+ *
+ * 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.
+ */
+
+#ifndef PSYCOPG_MICROPROTOCOLS_H
+#define PSYCOPG_MICROPROTOCOLS_H 1
+
+#include <Python.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** adapters registry **/
+
+extern PyObject *psyco_adapters;
+
+/** the names of the three mandatory methods **/
+
+#define MICROPROTOCOLS_GETQUOTED_NAME "getquoted"
+#define MICROPROTOCOLS_GETSTRING_NAME "getstring"
+#define MICROPROTOCOLS_GETBINARY_NAME "getbinary"
+
+/** exported functions **/
+
+/* used by module.c to init the microprotocols system */
+extern int microprotocols_init(PyObject *dict);
+extern int microprotocols_add(
+ PyTypeObject *type, PyObject *proto, PyObject *cast);
+extern PyObject *microprotocols_adapt(
+ PyObject *obj, PyObject *proto, PyObject *alt);
+
+extern PyObject *
+ psyco_microprotocols_adapt(Cursor* self, PyObject *args);
+#define psyco_microprotocols_adapt_doc \
+ "adapt(obj, protocol, alternate) -> adapt obj to given protocol"
+
+#endif /* !defined(PSYCOPG_MICROPROTOCOLS_H) */
diff --git a/Modules/_sqlite/module.c b/Modules/_sqlite/module.c
new file mode 100644
index 0000000..70993d0
--- /dev/null
+++ b/Modules/_sqlite/module.c
@@ -0,0 +1,290 @@
+/* module.c - the module itself
+ *
+ * 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 "connection.h"
+#include "statement.h"
+#include "cursor.h"
+#include "cache.h"
+#include "prepare_protocol.h"
+#include "microprotocols.h"
+#include "row.h"
+
+#if SQLITE_VERSION_NUMBER >= 3003003
+#define HAVE_SHARED_CACHE
+#endif
+
+/* static objects at module-level */
+
+PyObject* Error, *Warning, *InterfaceError, *DatabaseError, *InternalError,
+ *OperationalError, *ProgrammingError, *IntegrityError, *DataError,
+ *NotSupportedError, *OptimizedUnicode;
+
+PyObject* time_time;
+PyObject* time_sleep;
+
+PyObject* converters;
+
+static PyObject* module_connect(PyObject* self, PyObject* args, PyObject*
+ kwargs)
+{
+ /* Python seems to have no way of extracting a single keyword-arg at
+ * C-level, so this code is redundant with the one in connection_init in
+ * connection.c and must always be copied from there ... */
+
+ static char *kwlist[] = {"database", "timeout", "detect_types", "isolation_level", "check_same_thread", "factory", "cached_statements", NULL, NULL};
+ char* database;
+ int detect_types = 0;
+ PyObject* isolation_level;
+ PyObject* factory = NULL;
+ int check_same_thread = 1;
+ int cached_statements;
+ double timeout = 5.0;
+
+ PyObject* result;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|diOiOi", kwlist,
+ &database, &timeout, &detect_types, &isolation_level, &check_same_thread, &factory, &cached_statements))
+ {
+ return NULL;
+ }
+
+ if (factory == NULL) {
+ factory = (PyObject*)&ConnectionType;
+ }
+
+ result = PyObject_Call(factory, args, kwargs);
+
+ return result;
+}
+
+static PyObject* module_complete(PyObject* self, PyObject* args, PyObject*
+ kwargs)
+{
+ static char *kwlist[] = {"statement", NULL, NULL};
+ char* statement;
+
+ PyObject* result;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s", kwlist, &statement))
+ {
+ return NULL;
+ }
+
+ if (sqlite3_complete(statement)) {
+ result = Py_True;
+ } else {
+ result = Py_False;
+ }
+
+ Py_INCREF(result);
+
+ return result;
+}
+
+#ifdef HAVE_SHARED_CACHE
+static PyObject* module_enable_shared_cache(PyObject* self, PyObject* args, PyObject*
+ kwargs)
+{
+ static char *kwlist[] = {"do_enable", NULL, NULL};
+ int do_enable;
+ int rc;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i", kwlist, &do_enable))
+ {
+ return NULL;
+ }
+
+ rc = sqlite3_enable_shared_cache(do_enable);
+
+ if (rc != SQLITE_OK) {
+ PyErr_SetString(OperationalError, "Changing the shared_cache flag failed");
+ return NULL;
+ } else {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+}
+#endif /* HAVE_SHARED_CACHE */
+
+static PyObject* module_register_adapter(PyObject* self, PyObject* args, PyObject* kwargs)
+{
+ PyTypeObject* type;
+ PyObject* caster;
+
+ if (!PyArg_ParseTuple(args, "OO", &type, &caster)) {
+ return NULL;
+ }
+
+ microprotocols_add(type, (PyObject*)&SQLitePrepareProtocolType, caster);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject* module_register_converter(PyObject* self, PyObject* args, PyObject* kwargs)
+{
+ PyObject* name;
+ PyObject* callable;
+
+ if (!PyArg_ParseTuple(args, "OO", &name, &callable)) {
+ return NULL;
+ }
+
+ PyDict_SetItem(converters, name, callable);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+void converters_init(PyObject* dict)
+{
+ converters = PyDict_New();
+
+ PyDict_SetItemString(dict, "converters", converters);
+}
+
+static PyMethodDef module_methods[] = {
+ {"connect", (PyCFunction)module_connect, METH_VARARGS|METH_KEYWORDS, PyDoc_STR("Creates a connection.")},
+ {"complete_statement", (PyCFunction)module_complete, METH_VARARGS|METH_KEYWORDS, PyDoc_STR("Checks if a string contains a complete SQL statement.")},
+#ifdef HAVE_SHARED_CACHE
+ {"enable_shared_cache", (PyCFunction)module_enable_shared_cache, METH_VARARGS|METH_KEYWORDS, PyDoc_STR("Enable or disable shared cache mode for the calling thread.")},
+#endif
+ {"register_adapter", (PyCFunction)module_register_adapter, METH_VARARGS, PyDoc_STR("Registers an adapter with pysqlite's adapter registry.")},
+ {"register_converter", (PyCFunction)module_register_converter, METH_VARARGS, PyDoc_STR("Registers a converter with pysqlite.")},
+ {"adapt", (PyCFunction)psyco_microprotocols_adapt, METH_VARARGS, psyco_microprotocols_adapt_doc},
+ {NULL, NULL}
+};
+
+PyMODINIT_FUNC init_sqlite3(void)
+{
+ PyObject *module, *dict;
+ PyObject* time_module;
+
+ module = Py_InitModule("_sqlite3", module_methods);
+
+ if (
+ (row_setup_types() < 0) ||
+ (cursor_setup_types() < 0) ||
+ (connection_setup_types() < 0) ||
+ (cache_setup_types() < 0) ||
+ (statement_setup_types() < 0) ||
+ (prepare_protocol_setup_types() < 0)
+ ) {
+ return;
+ }
+
+ Py_INCREF(&ConnectionType);
+ PyModule_AddObject(module, "Connection", (PyObject*) &ConnectionType);
+ Py_INCREF(&CursorType);
+ PyModule_AddObject(module, "Cursor", (PyObject*) &CursorType);
+ Py_INCREF(&CacheType);
+ PyModule_AddObject(module, "Statement", (PyObject*)&StatementType);
+ Py_INCREF(&StatementType);
+ PyModule_AddObject(module, "Cache", (PyObject*) &CacheType);
+ Py_INCREF(&SQLitePrepareProtocolType);
+ PyModule_AddObject(module, "PrepareProtocol", (PyObject*) &SQLitePrepareProtocolType);
+ Py_INCREF(&RowType);
+ PyModule_AddObject(module, "Row", (PyObject*) &RowType);
+
+ if (!(dict = PyModule_GetDict(module)))
+ {
+ goto error;
+ }
+
+ /*** Create DB-API Exception hierarchy */
+
+ Error = PyErr_NewException("sqlite3.Error", PyExc_StandardError, NULL);
+ PyDict_SetItemString(dict, "Error", Error);
+
+ Warning = PyErr_NewException("sqlite3.Warning", PyExc_StandardError, NULL);
+ PyDict_SetItemString(dict, "Warning", Warning);
+
+ /* Error subclasses */
+
+ InterfaceError = PyErr_NewException("sqlite3.InterfaceError", Error, NULL);
+ PyDict_SetItemString(dict, "InterfaceError", InterfaceError);
+
+ DatabaseError = PyErr_NewException("sqlite3.DatabaseError", Error, NULL);
+ PyDict_SetItemString(dict, "DatabaseError", DatabaseError);
+
+ /* DatabaseError subclasses */
+
+ InternalError = PyErr_NewException("sqlite3.InternalError", DatabaseError, NULL);
+ PyDict_SetItemString(dict, "InternalError", InternalError);
+
+ OperationalError = PyErr_NewException("sqlite3.OperationalError", DatabaseError, NULL);
+ PyDict_SetItemString(dict, "OperationalError", OperationalError);
+
+ ProgrammingError = PyErr_NewException("sqlite3.ProgrammingError", DatabaseError, NULL);
+ PyDict_SetItemString(dict, "ProgrammingError", ProgrammingError);
+
+ IntegrityError = PyErr_NewException("sqlite3.IntegrityError", DatabaseError,NULL);
+ PyDict_SetItemString(dict, "IntegrityError", IntegrityError);
+
+ DataError = PyErr_NewException("sqlite3.DataError", DatabaseError, NULL);
+ PyDict_SetItemString(dict, "DataError", DataError);
+
+ NotSupportedError = PyErr_NewException("sqlite3.NotSupportedError", DatabaseError, NULL);
+ PyDict_SetItemString(dict, "NotSupportedError", NotSupportedError);
+
+ Py_INCREF((PyObject*)&PyCell_Type);
+ OptimizedUnicode = (PyObject*)&PyCell_Type;
+ PyDict_SetItemString(dict, "OptimizedUnicode", OptimizedUnicode);
+
+ PyDict_SetItemString(dict, "PARSE_DECLTYPES", PyInt_FromLong(PARSE_DECLTYPES));
+ PyDict_SetItemString(dict, "PARSE_COLNAMES", PyInt_FromLong(PARSE_COLNAMES));
+
+ PyDict_SetItemString(dict, "version", PyString_FromString(PYSQLITE_VERSION));
+ PyDict_SetItemString(dict, "sqlite_version", PyString_FromString(sqlite3_libversion()));
+
+ /* initialize microprotocols layer */
+ microprotocols_init(dict);
+
+ /* initialize the default converters */
+ converters_init(dict);
+
+ time_module = PyImport_ImportModule("time");
+ time_time = PyObject_GetAttrString(time_module, "time");
+ time_sleep = PyObject_GetAttrString(time_module, "sleep");
+
+ /* Original comment form _bsddb.c in the Python core. This is also still
+ * needed nowadays for Python 2.3/2.4.
+ *
+ * PyEval_InitThreads is called here due to a quirk in python 1.5
+ * - 2.2.1 (at least) according to Russell Williamson <merel@wt.net>:
+ * The global interepreter lock is not initialized until the first
+ * thread is created using thread.start_new_thread() or fork() is
+ * called. that would cause the ALLOW_THREADS here to segfault due
+ * to a null pointer reference if no threads or child processes
+ * have been created. This works around that and is a no-op if
+ * threads have already been initialized.
+ * (see pybsddb-users mailing list post on 2002-08-07)
+ */
+ PyEval_InitThreads();
+
+error:
+ if (PyErr_Occurred())
+ {
+ PyErr_SetString(PyExc_ImportError, "_sqlite3: init failed");
+ }
+}
diff --git a/Modules/_sqlite/module.h b/Modules/_sqlite/module.h
new file mode 100644
index 0000000..75fe29d
--- /dev/null
+++ b/Modules/_sqlite/module.h
@@ -0,0 +1,53 @@
+/* module.h - definitions for the module
+ *
+ * Copyright (C) 2004-2005 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.
+ */
+
+#ifndef PYSQLITE_MODULE_H
+#define PYSQLITE_MODULE_H
+#include "Python.h"
+
+extern PyObject* Error;
+extern PyObject* Warning;
+extern PyObject* InterfaceError;
+extern PyObject* DatabaseError;
+extern PyObject* InternalError;
+extern PyObject* OperationalError;
+extern PyObject* ProgrammingError;
+extern PyObject* IntegrityError;
+extern PyObject* DataError;
+extern PyObject* NotSupportedError;
+
+extern PyObject* OptimizedUnicode;
+
+/* the functions time.time() and time.sleep() */
+extern PyObject* time_time;
+extern PyObject* time_sleep;
+
+/* A dictionary, mapping colum types (INTEGER, VARCHAR, etc.) to converter
+ * functions, that convert the SQL value to the appropriate Python value.
+ * The key is uppercase.
+ */
+extern PyObject* converters;
+
+#define PARSE_DECLTYPES 1
+#define PARSE_COLNAMES 2
+#endif
diff --git a/Modules/_sqlite/prepare_protocol.c b/Modules/_sqlite/prepare_protocol.c
new file mode 100644
index 0000000..2e8349c
--- /dev/null
+++ b/Modules/_sqlite/prepare_protocol.c
@@ -0,0 +1,84 @@
+/* prepare_protocol.c - the protocol for preparing values for SQLite
+ *
+ * Copyright (C) 2005 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 "prepare_protocol.h"
+
+int prepare_protocol_init(SQLitePrepareProtocol* self, PyObject* args, PyObject* kwargs)
+{
+ return 0;
+}
+
+void prepare_protocol_dealloc(SQLitePrepareProtocol* self)
+{
+ self->ob_type->tp_free((PyObject*)self);
+}
+
+PyTypeObject SQLitePrepareProtocolType= {
+ PyObject_HEAD_INIT(NULL)
+ 0, /* ob_size */
+ "pysqlite2.dbapi2.PrepareProtocol", /* tp_name */
+ sizeof(SQLitePrepareProtocol), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)prepare_protocol_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, /* tp_flags */
+ 0, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)prepare_protocol_init, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+ 0 /* tp_free */
+};
+
+extern int prepare_protocol_setup_types(void)
+{
+ SQLitePrepareProtocolType.tp_new = PyType_GenericNew;
+ SQLitePrepareProtocolType.ob_type= &PyType_Type;
+ return PyType_Ready(&SQLitePrepareProtocolType);
+}
diff --git a/Modules/_sqlite/prepare_protocol.h b/Modules/_sqlite/prepare_protocol.h
new file mode 100644
index 0000000..2fc4f61
--- /dev/null
+++ b/Modules/_sqlite/prepare_protocol.h
@@ -0,0 +1,41 @@
+/* prepare_protocol.h - the protocol for preparing values for SQLite
+ *
+ * Copyright (C) 2005 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.
+ */
+
+#ifndef PYSQLITE_PREPARE_PROTOCOL_H
+#define PYSQLITE_PREPARE_PROTOCOL_H
+#include "Python.h"
+
+typedef struct
+{
+ PyObject_HEAD
+} SQLitePrepareProtocol;
+
+extern PyTypeObject SQLitePrepareProtocolType;
+
+int prepare_protocol_init(SQLitePrepareProtocol* self, PyObject* args, PyObject* kwargs);
+void prepare_protocol_dealloc(SQLitePrepareProtocol* self);
+
+int prepare_protocol_setup_types(void);
+
+#define UNKNOWN (-1)
+#endif
diff --git a/Modules/_sqlite/row.c b/Modules/_sqlite/row.c
new file mode 100644
index 0000000..97b538d
--- /dev/null
+++ b/Modules/_sqlite/row.c
@@ -0,0 +1,195 @@
+/* row.c - an enhanced tuple for database rows
+ *
+ * Copyright (C) 2005 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 "row.h"
+#include "cursor.h"
+
+void row_dealloc(Row* self)
+{
+ Py_XDECREF(self->data);
+ Py_XDECREF(self->description);
+
+ self->ob_type->tp_free((PyObject*)self);
+}
+
+int row_init(Row* self, PyObject* args, PyObject* kwargs)
+{
+ PyObject* data;
+ Cursor* cursor;
+
+ self->data = 0;
+ self->description = 0;
+
+ if (!PyArg_ParseTuple(args, "OO", &cursor, &data)) {
+ return -1;
+ }
+
+ if (!PyObject_IsInstance((PyObject*)cursor, (PyObject*)&CursorType)) {
+ PyErr_SetString(PyExc_TypeError, "instance of cursor required for first argument");
+ return -1;
+ }
+
+ if (!PyTuple_Check(data)) {
+ PyErr_SetString(PyExc_TypeError, "tuple required for second argument");
+ return -1;
+ }
+
+ Py_INCREF(data);
+ self->data = data;
+
+ Py_INCREF(cursor->description);
+ self->description = cursor->description;
+
+ return 0;
+}
+
+PyObject* row_subscript(Row* self, PyObject* idx)
+{
+ long _idx;
+ char* key;
+ int nitems, i;
+ char* compare_key;
+
+ char* p1;
+ char* p2;
+
+ PyObject* item;
+
+ if (PyInt_Check(idx)) {
+ _idx = PyInt_AsLong(idx);
+ item = PyTuple_GetItem(self->data, _idx);
+ if (item) {
+ Py_INCREF(item);
+ }
+ return item;
+ } else if (PyString_Check(idx)) {
+ key = PyString_AsString(idx);
+
+ nitems = PyTuple_Size(self->description);
+
+ for (i = 0; i < nitems; i++) {
+ compare_key = PyString_AsString(PyTuple_GET_ITEM(PyTuple_GET_ITEM(self->description, i), 0));
+
+ p1 = key;
+ p2 = compare_key;
+
+ while (1) {
+ if ((*p1 == (char)0) || (*p2 == (char)0)) {
+ break;
+ }
+
+ if ((*p1 | 0x20) != (*p2 | 0x20)) {
+ break;
+ }
+
+ p1++;
+ p2++;
+ }
+
+ if ((*p1 == (char)0) && (*p2 == (char)0)) {
+ /* found item */
+ item = PyTuple_GetItem(self->data, i);
+ Py_INCREF(item);
+ return item;
+ }
+
+ }
+
+ PyErr_SetString(PyExc_IndexError, "No item with that key");
+ return NULL;
+ } else if (PySlice_Check(idx)) {
+ PyErr_SetString(PyExc_ValueError, "slices not implemented, yet");
+ return NULL;
+ } else {
+ PyErr_SetString(PyExc_IndexError, "Index must be int or string");
+ return NULL;
+ }
+}
+
+int row_length(Row* self, PyObject* args, PyObject* kwargs)
+{
+ return PyTuple_GET_SIZE(self->data);
+}
+
+static int row_print(Row* self, FILE *fp, int flags)
+{
+ return (&PyTuple_Type)->tp_print(self->data, fp, flags);
+}
+
+
+PyMappingMethods row_as_mapping = {
+ /* mp_length */ (inquiry)row_length,
+ /* mp_subscript */ (binaryfunc)row_subscript,
+ /* mp_ass_subscript */ (objobjargproc)0,
+};
+
+
+PyTypeObject RowType = {
+ PyObject_HEAD_INIT(NULL)
+ 0, /* ob_size */
+ "pysqlite2.dbapi2.Row", /* tp_name */
+ sizeof(Row), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)row_dealloc, /* tp_dealloc */
+ (printfunc)row_print, /* 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 */
+ 0, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)row_init, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+ 0 /* tp_free */
+};
+
+extern int row_setup_types(void)
+{
+ RowType.tp_new = PyType_GenericNew;
+ RowType.tp_as_mapping = &row_as_mapping;
+ return PyType_Ready(&RowType);
+}
diff --git a/Modules/_sqlite/row.h b/Modules/_sqlite/row.h
new file mode 100644
index 0000000..c6e083c
--- /dev/null
+++ b/Modules/_sqlite/row.h
@@ -0,0 +1,39 @@
+/* row.h - an enhanced tuple for database rows
+ *
+ * Copyright (C) 2005 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.
+ */
+
+#ifndef PYSQLITE_ROW_H
+#define PYSQLITE_ROW_H
+#include "Python.h"
+
+typedef struct _Row
+{
+ PyObject_HEAD
+ PyObject* data;
+ PyObject* description;
+} Row;
+
+extern PyTypeObject RowType;
+
+int row_setup_types(void);
+
+#endif
diff --git a/Modules/_sqlite/statement.c b/Modules/_sqlite/statement.c
new file mode 100644
index 0000000..a2c0f13
--- /dev/null
+++ b/Modules/_sqlite/statement.c
@@ -0,0 +1,285 @@
+/* statement.c - the statement type
+ *
+ * Copyright (C) 2005-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 "statement.h"
+#include "connection.h"
+
+/* prototypes */
+int check_remaining_sql(const char* tail);
+
+typedef enum {
+ LINECOMMENT_1,
+ IN_LINECOMMENT,
+ COMMENTSTART_1,
+ IN_COMMENT,
+ COMMENTEND_1,
+ NORMAL
+} parse_remaining_sql_state;
+
+int statement_create(Statement* self, Connection* connection, PyObject* sql)
+{
+ const char* tail;
+ int rc;
+ PyObject* sql_str;
+ char* sql_cstr;
+
+ self->st = NULL;
+
+ self->st = NULL;
+ self->in_use = 0;
+
+ if (PyString_Check(sql)) {
+ sql_str = sql;
+ Py_INCREF(sql_str);
+ } else if (PyUnicode_Check(sql)) {
+ sql_str = PyUnicode_AsUTF8String(sql);
+ if (!sql_str) {
+ rc = PYSQLITE_SQL_WRONG_TYPE;
+ return rc;
+ }
+ } else {
+ rc = PYSQLITE_SQL_WRONG_TYPE;
+ return rc;
+ }
+
+ self->sql = sql_str;
+
+ sql_cstr = PyString_AsString(sql_str);
+
+ rc = sqlite3_prepare(connection->db,
+ sql_cstr,
+ -1,
+ &self->st,
+ &tail);
+
+ self->db = connection->db;
+
+ if (rc == SQLITE_OK && check_remaining_sql(tail)) {
+ (void)sqlite3_finalize(self->st);
+ rc = PYSQLITE_TOO_MUCH_SQL;
+ }
+
+ return rc;
+}
+
+int statement_recompile(Statement* self)
+{
+ const char* tail;
+ int rc;
+ char* sql_cstr;
+ sqlite3_stmt* new_st;
+
+ sql_cstr = PyString_AsString(self->sql);
+
+ rc = sqlite3_prepare(self->db,
+ sql_cstr,
+ -1,
+ &new_st,
+ &tail);
+
+ if (rc == SQLITE_OK) {
+ (void)sqlite3_transfer_bindings(self->st, new_st);
+
+ (void)sqlite3_finalize(self->st);
+ self->st = new_st;
+ }
+
+ return rc;
+}
+
+int statement_finalize(Statement* self)
+{
+ int rc;
+
+ rc = SQLITE_OK;
+ if (self->st) {
+ Py_BEGIN_ALLOW_THREADS
+ rc = sqlite3_finalize(self->st);
+ Py_END_ALLOW_THREADS
+ self->st = NULL;
+ }
+
+ self->in_use = 0;
+
+ return rc;
+}
+
+int statement_reset(Statement* self)
+{
+ int rc;
+
+ rc = SQLITE_OK;
+
+ if (self->in_use && self->st) {
+ Py_BEGIN_ALLOW_THREADS
+ rc = sqlite3_reset(self->st);
+ Py_END_ALLOW_THREADS
+
+ if (rc == SQLITE_OK) {
+ self->in_use = 0;
+ }
+ }
+
+ return rc;
+}
+
+void statement_mark_dirty(Statement* self)
+{
+ self->in_use = 1;
+}
+
+void statement_dealloc(Statement* self)
+{
+ int rc;
+
+ if (self->st) {
+ Py_BEGIN_ALLOW_THREADS
+ rc = sqlite3_finalize(self->st);
+ Py_END_ALLOW_THREADS
+ }
+
+ self->st = NULL;
+
+ Py_XDECREF(self->sql);
+
+ self->ob_type->tp_free((PyObject*)self);
+}
+
+/*
+ * Checks if there is anything left in an SQL string after SQLite compiled it.
+ * This is used to check if somebody tried to execute more than one SQL command
+ * with one execute()/executemany() command, which the DB-API and we don't
+ * allow.
+ *
+ * Returns 1 if there is more left than should be. 0 if ok.
+ */
+int check_remaining_sql(const char* tail)
+{
+ const char* pos = tail;
+
+ parse_remaining_sql_state state = NORMAL;
+
+ for (;;) {
+ switch (*pos) {
+ case 0:
+ return 0;
+ case '-':
+ if (state == NORMAL) {
+ state = LINECOMMENT_1;
+ } else if (state == LINECOMMENT_1) {
+ state = IN_LINECOMMENT;
+ }
+ break;
+ case ' ':
+ case '\t':
+ break;
+ case '\n':
+ case 13:
+ if (state == IN_LINECOMMENT) {
+ state = NORMAL;
+ }
+ break;
+ case '/':
+ if (state == NORMAL) {
+ state = COMMENTSTART_1;
+ } else if (state == COMMENTEND_1) {
+ state = NORMAL;
+ } else if (state == COMMENTSTART_1) {
+ return 1;
+ }
+ break;
+ case '*':
+ if (state == NORMAL) {
+ return 1;
+ } else if (state == LINECOMMENT_1) {
+ return 1;
+ } else if (state == COMMENTSTART_1) {
+ state = IN_COMMENT;
+ } else if (state == IN_COMMENT) {
+ state = COMMENTEND_1;
+ }
+ break;
+ default:
+ if (state == COMMENTEND_1) {
+ state = IN_COMMENT;
+ } else if (state == IN_LINECOMMENT) {
+ } else if (state == IN_COMMENT) {
+ } else {
+ return 1;
+ }
+ }
+
+ pos++;
+ }
+
+ return 0;
+}
+
+PyTypeObject StatementType = {
+ PyObject_HEAD_INIT(NULL)
+ 0, /* ob_size */
+ "pysqlite2.dbapi2.Statement", /* tp_name */
+ sizeof(Statement), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)statement_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, /* tp_flags */
+ 0, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)0, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+ 0 /* tp_free */
+};
+
+extern int statement_setup_types(void)
+{
+ StatementType.tp_new = PyType_GenericNew;
+ return PyType_Ready(&StatementType);
+}
diff --git a/Modules/_sqlite/statement.h b/Modules/_sqlite/statement.h
new file mode 100644
index 0000000..8cf52eb
--- /dev/null
+++ b/Modules/_sqlite/statement.h
@@ -0,0 +1,55 @@
+/* statement.h - definitions for the statement type
+ *
+ * Copyright (C) 2005 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.
+ */
+
+#ifndef PYSQLITE_STATEMENT_H
+#define PYSQLITE_STATEMENT_H
+#include "Python.h"
+
+#include "connection.h"
+#include "sqlite3.h"
+
+#define PYSQLITE_TOO_MUCH_SQL (-100)
+#define PYSQLITE_SQL_WRONG_TYPE (-101)
+
+typedef struct
+{
+ PyObject_HEAD
+ sqlite3* db;
+ sqlite3_stmt* st;
+ PyObject* sql;
+ int in_use;
+} Statement;
+
+extern PyTypeObject StatementType;
+
+int statement_create(Statement* self, Connection* connection, PyObject* sql);
+void statement_dealloc(Statement* self);
+
+int statement_recompile(Statement* self);
+int statement_finalize(Statement* self);
+int statement_reset(Statement* self);
+void statement_mark_dirty(Statement* self);
+
+int statement_setup_types(void);
+
+#endif
diff --git a/Modules/_sqlite/util.c b/Modules/_sqlite/util.c
new file mode 100644
index 0000000..ec400a1
--- /dev/null
+++ b/Modules/_sqlite/util.c
@@ -0,0 +1,147 @@
+/* util.c - various utility functions
+ *
+ * Copyright (C) 2005 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 "module.h"
+#include "connection.h"
+
+/*
+ * it's not so trivial to write a portable sleep in C. For now, the simplest
+ * solution is to just use Python's sleep().
+ */
+void pysqlite_sleep(double seconds)
+{
+ PyObject* ret;
+
+ ret = PyObject_CallFunction(time_sleep, "d", seconds);
+ Py_DECREF(ret);
+}
+
+double pysqlite_time(void)
+{
+ PyObject* ret;
+ double time;
+
+ ret = PyObject_CallFunction(time_time, "");
+ time = PyFloat_AsDouble(ret);
+ Py_DECREF(ret);
+
+ return time;
+}
+
+int _sqlite_step_with_busyhandler(sqlite3_stmt* statement, Connection* connection
+)
+{
+ int rc;
+
+ Py_BEGIN_ALLOW_THREADS
+ rc = sqlite3_step(statement);
+ Py_END_ALLOW_THREADS
+
+ return rc;
+}
+
+/**
+ * Checks the SQLite error code and sets the appropriate DB-API exception.
+ * Returns the error code (0 means no error occured).
+ */
+int _seterror(sqlite3* db)
+{
+ int errorcode;
+
+ errorcode = sqlite3_errcode(db);
+
+ switch (errorcode)
+ {
+ case SQLITE_OK:
+ PyErr_Clear();
+ break;
+ case SQLITE_ERROR:
+ PyErr_SetString(OperationalError, sqlite3_errmsg(db));
+ break;
+ case SQLITE_INTERNAL:
+ PyErr_SetString(InternalError, sqlite3_errmsg(db));
+ break;
+ case SQLITE_PERM:
+ PyErr_SetString(OperationalError, sqlite3_errmsg(db));
+ break;
+ case SQLITE_ABORT:
+ PyErr_SetString(OperationalError, sqlite3_errmsg(db));
+ break;
+ case SQLITE_BUSY:
+ PyErr_SetString(OperationalError, sqlite3_errmsg(db));
+ break;
+ case SQLITE_LOCKED:
+ PyErr_SetString(OperationalError, sqlite3_errmsg(db));
+ break;
+ case SQLITE_NOMEM:
+ (void)PyErr_NoMemory();
+ break;
+ case SQLITE_READONLY:
+ PyErr_SetString(OperationalError, sqlite3_errmsg(db));
+ break;
+ case SQLITE_INTERRUPT:
+ PyErr_SetString(OperationalError, sqlite3_errmsg(db));
+ break;
+ case SQLITE_IOERR:
+ PyErr_SetString(OperationalError, sqlite3_errmsg(db));
+ break;
+ case SQLITE_CORRUPT:
+ PyErr_SetString(DatabaseError, sqlite3_errmsg(db));
+ break;
+ case SQLITE_NOTFOUND:
+ PyErr_SetString(InternalError, sqlite3_errmsg(db));
+ break;
+ case SQLITE_FULL:
+ PyErr_SetString(OperationalError, sqlite3_errmsg(db));
+ break;
+ case SQLITE_CANTOPEN:
+ PyErr_SetString(OperationalError, sqlite3_errmsg(db));
+ break;
+ case SQLITE_PROTOCOL:
+ PyErr_SetString(OperationalError, sqlite3_errmsg(db));
+ break;
+ case SQLITE_EMPTY:
+ PyErr_SetString(OperationalError, sqlite3_errmsg(db));
+ break;
+ case SQLITE_SCHEMA:
+ PyErr_SetString(OperationalError, sqlite3_errmsg(db));
+ break;
+ case SQLITE_TOOBIG:
+ PyErr_SetString(DataError, sqlite3_errmsg(db));
+ break;
+ case SQLITE_CONSTRAINT:
+ PyErr_SetString(IntegrityError, sqlite3_errmsg(db));
+ break;
+ case SQLITE_MISMATCH:
+ PyErr_SetString(IntegrityError, sqlite3_errmsg(db));
+ break;
+ case SQLITE_MISUSE:
+ PyErr_SetString(ProgrammingError, sqlite3_errmsg(db));
+ break;
+ default:
+ PyErr_SetString(DatabaseError, sqlite3_errmsg(db));
+ }
+
+ return errorcode;
+}
+
diff --git a/Modules/_sqlite/util.h b/Modules/_sqlite/util.h
new file mode 100644
index 0000000..6e74b2d
--- /dev/null
+++ b/Modules/_sqlite/util.h
@@ -0,0 +1,40 @@
+/* util.h - various utility functions
+ *
+ * Copyright (C) 2005 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.
+ */
+
+#ifndef PYSQLITE_UTIL_H
+#define PYSQLITE_UTIL_H
+#include "Python.h"
+#include "pythread.h"
+#include "sqlite3.h"
+#include "connection.h"
+
+void pysqlite_sleep(double seconds);
+
+int _sqlite_step_with_busyhandler(sqlite3_stmt* statement, Connection* connection);
+
+/**
+ * Checks the SQLite error code and sets the appropriate DB-API exception.
+ * Returns the error code (0 means no error occured).
+ */
+int _seterror(sqlite3* db);
+#endif