[Python-checkins] r43533 - in python/trunk: Modules/_sqlite/cursor.c Modules/_sqlite/statement.c Modules/_sqlite/statement.h setup.py

anthony.baxter python-checkins at python.org
Sat Apr 1 10:36:28 CEST 2006


Author: anthony.baxter
Date: Sat Apr  1 10:36:27 2006
New Revision: 43533

Modified:
   python/trunk/Modules/_sqlite/cursor.c
   python/trunk/Modules/_sqlite/statement.c
   python/trunk/Modules/_sqlite/statement.h
   python/trunk/setup.py
Log:
backport r243 from the pysqlite2 svn repository - lowers the required version
of SQLite3 from 3.2.2 to 3.0.8, by providing an alternative to 
sqlite3_transfer_bindings. setup.py also handles the common (in debian
and ubuntu, at least) case of a buggy sqlite3.h SQLITE_VERSION_NUMBER. 


Modified: python/trunk/Modules/_sqlite/cursor.c
==============================================================================
--- python/trunk/Modules/_sqlite/cursor.c	(original)
+++ python/trunk/Modules/_sqlite/cursor.c	Sat Apr  1 10:36:27 2006
@@ -24,8 +24,6 @@
 #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)
@@ -189,53 +187,6 @@
     }
 }
 
-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;
@@ -394,7 +345,6 @@
     PyObject* parameters_list = NULL;
     PyObject* parameters_iter = NULL;
     PyObject* parameters = NULL;
-    int num_params;
     int i;
     int rc;
     PyObject* func_args;
@@ -403,11 +353,7 @@
     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)) {
@@ -557,10 +503,6 @@
     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) {
@@ -569,71 +511,9 @@
 
         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;
-                }
-            }
+        statement_bind_parameters(self->statement, parameters);
+        if (PyErr_Occurred()) {
+            goto error;
         }
 
         build_row_cast_map(self);
@@ -642,7 +522,7 @@
         if (rc != SQLITE_DONE && rc != SQLITE_ROW) {
             rc = statement_reset(self->statement);
             if (rc == SQLITE_SCHEMA) {
-                rc = statement_recompile(self->statement);
+                rc = statement_recompile(self->statement, parameters);
                 if (rc == SQLITE_OK) {
                     rc = _sqlite_step_with_busyhandler(self->statement->st, self->connection);
                 } else {

Modified: python/trunk/Modules/_sqlite/statement.c
==============================================================================
--- python/trunk/Modules/_sqlite/statement.c	(original)
+++ python/trunk/Modules/_sqlite/statement.c	Sat Apr  1 10:36:27 2006
@@ -22,7 +22,10 @@
  */
 
 #include "statement.h"
+#include "cursor.h"
 #include "connection.h"
+#include "microprotocols.h"
+#include "prepare_protocol.h"
 
 /* prototypes */
 int check_remaining_sql(const char* tail);
@@ -82,7 +85,136 @@
     return rc;
 }
 
-int statement_recompile(Statement* self)
+int statement_bind_parameter(Statement* 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->st, pos);
+    } else if (PyInt_Check(parameter)) {
+        longval = PyInt_AsLong(parameter);
+        rc = sqlite3_bind_int64(self->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->st, pos, (sqlite_int64)longlongval);
+#endif
+    } else if (PyFloat_Check(parameter)) {
+        rc = sqlite3_bind_double(self->st, pos, PyFloat_AsDouble(parameter));
+    } else if (PyBuffer_Check(parameter)) {
+        if (PyObject_AsCharBuffer(parameter, &buffer, &buflen) == 0) {
+            rc = sqlite3_bind_blob(self->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->st, pos, string, -1, SQLITE_TRANSIENT);
+    } else if PyUnicode_Check(parameter) {
+        stringval = PyUnicode_AsUTF8String(parameter);
+        string = PyString_AsString(stringval);
+        rc = sqlite3_bind_text(self->st, pos, string, -1, SQLITE_TRANSIENT);
+        Py_DECREF(stringval);
+    } else {
+        rc = -1;
+    }
+
+    return rc;
+}
+
+void statement_bind_parameters(Statement* self, PyObject* parameters)
+{
+    PyObject* current_param;
+    PyObject* adapted;
+    const char* binding_name;
+    int i;
+    int rc;
+    int num_params_needed;
+    int num_params;
+
+    Py_BEGIN_ALLOW_THREADS
+    num_params_needed = sqlite3_bind_parameter_count(self->st);
+    Py_END_ALLOW_THREADS
+
+    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->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);
+                return;
+            }
+
+            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);
+                return;
+            }
+
+            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 = statement_bind_parameter(self, i, adapted);
+            Py_DECREF(adapted);
+
+            if (rc != SQLITE_OK) {
+                PyErr_Format(InterfaceError, "Error binding parameter :%s - probably unsupported type.", binding_name);
+                return;
+           }
+        }
+    } 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);
+            return;
+        }
+        for (i = 0; i < num_params; i++) {
+            current_param = PySequence_GetItem(parameters, i);
+            if (!current_param) {
+                return;
+            }
+            adapted = microprotocols_adapt(current_param, (PyObject*)&SQLitePrepareProtocolType, NULL);
+
+            if (adapted) {
+                Py_DECREF(current_param);
+            } else {
+                PyErr_Clear();
+                adapted = current_param;
+            }
+
+            rc = statement_bind_parameter(self, i + 1, adapted);
+            Py_DECREF(adapted);
+
+            if (rc != SQLITE_OK) {
+                PyErr_Format(InterfaceError, "Error binding parameter %d - probably unsupported type.", i);
+                return;
+            }
+        }
+    }
+}
+
+int statement_recompile(Statement* self, PyObject* params)
 {
     const char* tail;
     int rc;
@@ -98,7 +230,17 @@
                          &tail);
 
     if (rc == SQLITE_OK) {
+        /* The efficient sqlite3_transfer_bindings is only available in SQLite
+         * version 3.2.2 or later. For older SQLite releases, that might not
+         * even define SQLITE_VERSION_NUMBER, we do it the manual way.
+         */
+        #ifdef SQLITE_VERSION_NUMBER
+        #if SQLITE_VERSION_NUMBER >= 3002002
         (void)sqlite3_transfer_bindings(self->st, new_st);
+        #endif
+        #else
+        statement_bind_parameters(self, params);
+        #endif
 
         (void)sqlite3_finalize(self->st);
         self->st = new_st;

Modified: python/trunk/Modules/_sqlite/statement.h
==============================================================================
--- python/trunk/Modules/_sqlite/statement.h	(original)
+++ python/trunk/Modules/_sqlite/statement.h	Sat Apr  1 10:36:27 2006
@@ -45,7 +45,10 @@
 int statement_create(Statement* self, Connection* connection, PyObject* sql);
 void statement_dealloc(Statement* self);
 
-int statement_recompile(Statement* self);
+int statement_bind_parameter(Statement* self, int pos, PyObject* parameter);
+void statement_bind_parameters(Statement* self, PyObject* parameters);
+
+int statement_recompile(Statement* self, PyObject* parameters);
 int statement_finalize(Statement* self);
 int statement_reset(Statement* self);
 void statement_mark_dirty(Statement* self);

Modified: python/trunk/setup.py
==============================================================================
--- python/trunk/setup.py	(original)
+++ python/trunk/setup.py	Sat Apr  1 10:36:27 2006
@@ -690,6 +690,7 @@
             dblib_dir = None
 
         # The sqlite interface
+        sqlite_setup_debug = True   # verbose debug prints from this script?
 
         # We hunt for "#define SQLITE_VERSION_NUMBER nnnnn"
         # We need to find a version >= 3002002 (> sqlite version 3.2.2)
@@ -701,22 +702,37 @@
                              '/usr/local/include/sqlite',
                              '/usr/local/include/sqlite3',
                            ]
-        MIN_SQLITE_VERSION = 3002002
+        MIN_SQLITE_VERSION_NUMBER = 3000008
+        MIN_SQLITE_VERSION = "3.0.8"
         for d in sqlite_inc_paths + inc_dirs:
             f = os.path.join(d, "sqlite3.h")
             if os.path.exists(f):
-                if db_setup_debug: print "found %s"%f
+                if sqlite_setup_debug: print "sqlite: found %s"%f
                 f = open(f).read()
                 m = re.search(r"#define\WSQLITE_VERSION_NUMBER\W(\d+)", f)
                 if m:
                     sqlite_version = int(m.group(1))
-                    if sqlite_version >= MIN_SQLITE_VERSION:
+                    if sqlite_version >= MIN_SQLITE_VERSION_NUMBER:
                         # we win!
                         print "%s/sqlite3.h: version %s"%(d, sqlite_version)
                         sqlite_incdir = d
                         break
+                    elif sqlite_version == 3000000:
+                        # Bug in a common version out there where 
+                        # SQLITE_VERSION_NUMBER was set incorrectly
+                        if sqlite_setup_debug: 
+                            print "found buggy SQLITE_VERSION_NUMBER, checking"
+                        m = re.search(r'#define\WSQLITE_VERSION\W+"([\.\d]+)"',
+                                                                            f)
+                        if m:
+                            sqlite_version = m.group(1)
+                            if sqlite_version >= MIN_SQLITE_VERSION:
+                                print "%s/sqlite3.h: version %s"%(d, 
+                                                            sqlite_version)
+                                sqlite_incdir = d
+                                break
                     else:
-                        if db_setup_debug: 
+                        if sqlite_setup_debug: 
                             print "%s: version %d is too old, need >= %s"%(d,
                                         sqlite_version, MIN_SQLITE_VERSION)
         


More information about the Python-checkins mailing list