Skip to content

Commit 7d04e31

Browse files
author
anthony.baxter
committed
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. git-svn-id: http://svn.python.org/projects/python/trunk@43533 6015fed2-1504-0410-9fe1-9d1591cc4771
1 parent 6a442ae commit 7d04e31

4 files changed

Lines changed: 171 additions & 130 deletions

File tree

Modules/_sqlite/cursor.c

Lines changed: 4 additions & 124 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,6 @@
2424
#include "cursor.h"
2525
#include "module.h"
2626
#include "util.h"
27-
#include "microprotocols.h"
28-
#include "prepare_protocol.h"
2927

3028
/* used to decide wether to call PyInt_FromLong or PyLong_FromLongLong */
3129
#define INT32_MIN (-2147483647 - 1)
@@ -189,53 +187,6 @@ void build_row_cast_map(Cursor* self)
189187
}
190188
}
191189

192-
int _bind_parameter(Cursor* self, int pos, PyObject* parameter)
193-
{
194-
int rc = SQLITE_OK;
195-
long longval;
196-
#ifdef HAVE_LONG_LONG
197-
PY_LONG_LONG longlongval;
198-
#endif
199-
const char* buffer;
200-
char* string;
201-
int buflen;
202-
PyObject* stringval;
203-
204-
if (parameter == Py_None) {
205-
rc = sqlite3_bind_null(self->statement->st, pos);
206-
} else if (PyInt_Check(parameter)) {
207-
longval = PyInt_AsLong(parameter);
208-
rc = sqlite3_bind_int64(self->statement->st, pos, (sqlite_int64)longval);
209-
#ifdef HAVE_LONG_LONG
210-
} else if (PyLong_Check(parameter)) {
211-
longlongval = PyLong_AsLongLong(parameter);
212-
/* in the overflow error case, longlongval is -1, and an exception is set */
213-
rc = sqlite3_bind_int64(self->statement->st, pos, (sqlite_int64)longlongval);
214-
#endif
215-
} else if (PyFloat_Check(parameter)) {
216-
rc = sqlite3_bind_double(self->statement->st, pos, PyFloat_AsDouble(parameter));
217-
} else if (PyBuffer_Check(parameter)) {
218-
if (PyObject_AsCharBuffer(parameter, &buffer, &buflen) == 0) {
219-
rc = sqlite3_bind_blob(self->statement->st, pos, buffer, buflen, SQLITE_TRANSIENT);
220-
} else {
221-
PyErr_SetString(PyExc_ValueError, "could not convert BLOB to buffer");
222-
rc = -1;
223-
}
224-
} else if PyString_Check(parameter) {
225-
string = PyString_AsString(parameter);
226-
rc = sqlite3_bind_text(self->statement->st, pos, string, -1, SQLITE_TRANSIENT);
227-
} else if PyUnicode_Check(parameter) {
228-
stringval = PyUnicode_AsUTF8String(parameter);
229-
string = PyString_AsString(stringval);
230-
rc = sqlite3_bind_text(self->statement->st, pos, string, -1, SQLITE_TRANSIENT);
231-
Py_DECREF(stringval);
232-
} else {
233-
rc = -1;
234-
}
235-
236-
return rc;
237-
}
238-
239190
PyObject* _build_column_name(const char* colname)
240191
{
241192
const char* pos;
@@ -394,7 +345,6 @@ PyObject* _query_execute(Cursor* self, int multiple, PyObject* args)
394345
PyObject* parameters_list = NULL;
395346
PyObject* parameters_iter = NULL;
396347
PyObject* parameters = NULL;
397-
int num_params;
398348
int i;
399349
int rc;
400350
PyObject* func_args;
@@ -403,11 +353,7 @@ PyObject* _query_execute(Cursor* self, int multiple, PyObject* args)
403353
PY_LONG_LONG lastrowid;
404354
int statement_type;
405355
PyObject* descriptor;
406-
PyObject* current_param;
407-
PyObject* adapted;
408356
PyObject* second_argument = NULL;
409-
int num_params_needed;
410-
const char* binding_name;
411357
long rowcount = 0;
412358

413359
if (!check_thread(self->connection) || !check_connection(self->connection)) {
@@ -557,10 +503,6 @@ PyObject* _query_execute(Cursor* self, int multiple, PyObject* args)
557503
statement_reset(self->statement);
558504
statement_mark_dirty(self->statement);
559505

560-
Py_BEGIN_ALLOW_THREADS
561-
num_params_needed = sqlite3_bind_parameter_count(self->statement->st);
562-
Py_END_ALLOW_THREADS
563-
564506
while (1) {
565507
parameters = PyIter_Next(parameters_iter);
566508
if (!parameters) {
@@ -569,71 +511,9 @@ PyObject* _query_execute(Cursor* self, int multiple, PyObject* args)
569511

570512
statement_mark_dirty(self->statement);
571513

572-
if (PyDict_Check(parameters)) {
573-
/* parameters passed as dictionary */
574-
for (i = 1; i <= num_params_needed; i++) {
575-
Py_BEGIN_ALLOW_THREADS
576-
binding_name = sqlite3_bind_parameter_name(self->statement->st, i);
577-
Py_END_ALLOW_THREADS
578-
if (!binding_name) {
579-
PyErr_Format(ProgrammingError, "Binding %d has no name, but you supplied a dictionary (which has only names).", i);
580-
goto error;
581-
}
582-
583-
binding_name++; /* skip first char (the colon) */
584-
current_param = PyDict_GetItemString(parameters, binding_name);
585-
if (!current_param) {
586-
PyErr_Format(ProgrammingError, "You did not supply a value for binding %d.", i);
587-
goto error;
588-
}
589-
590-
Py_INCREF(current_param);
591-
adapted = microprotocols_adapt(current_param, (PyObject*)&SQLitePrepareProtocolType, NULL);
592-
if (adapted) {
593-
Py_DECREF(current_param);
594-
} else {
595-
PyErr_Clear();
596-
adapted = current_param;
597-
}
598-
599-
rc = _bind_parameter(self, i, adapted);
600-
Py_DECREF(adapted);
601-
602-
if (rc != SQLITE_OK) {
603-
PyErr_Format(InterfaceError, "Error binding parameter :%s - probably unsupported type.", binding_name);
604-
goto error;
605-
}
606-
}
607-
} else {
608-
/* parameters passed as sequence */
609-
num_params = PySequence_Length(parameters);
610-
if (num_params != num_params_needed) {
611-
PyErr_Format(ProgrammingError, "Incorrect number of bindings supplied. The current statement uses %d, and there are %d supplied.",
612-
num_params_needed, num_params);
613-
goto error;
614-
}
615-
for (i = 0; i < num_params; i++) {
616-
current_param = PySequence_GetItem(parameters, i);
617-
if (!current_param) {
618-
goto error;
619-
}
620-
adapted = microprotocols_adapt(current_param, (PyObject*)&SQLitePrepareProtocolType, NULL);
621-
622-
if (adapted) {
623-
Py_DECREF(current_param);
624-
} else {
625-
PyErr_Clear();
626-
adapted = current_param;
627-
}
628-
629-
rc = _bind_parameter(self, i + 1, adapted);
630-
Py_DECREF(adapted);
631-
632-
if (rc != SQLITE_OK) {
633-
PyErr_Format(InterfaceError, "Error binding parameter %d - probably unsupported type.", i);
634-
goto error;
635-
}
636-
}
514+
statement_bind_parameters(self->statement, parameters);
515+
if (PyErr_Occurred()) {
516+
goto error;
637517
}
638518

639519
build_row_cast_map(self);
@@ -642,7 +522,7 @@ PyObject* _query_execute(Cursor* self, int multiple, PyObject* args)
642522
if (rc != SQLITE_DONE && rc != SQLITE_ROW) {
643523
rc = statement_reset(self->statement);
644524
if (rc == SQLITE_SCHEMA) {
645-
rc = statement_recompile(self->statement);
525+
rc = statement_recompile(self->statement, parameters);
646526
if (rc == SQLITE_OK) {
647527
rc = _sqlite_step_with_busyhandler(self->statement->st, self->connection);
648528
} else {

Modules/_sqlite/statement.c

Lines changed: 143 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,10 @@
2222
*/
2323

2424
#include "statement.h"
25+
#include "cursor.h"
2526
#include "connection.h"
27+
#include "microprotocols.h"
28+
#include "prepare_protocol.h"
2629

2730
/* prototypes */
2831
int check_remaining_sql(const char* tail);
@@ -82,7 +85,136 @@ int statement_create(Statement* self, Connection* connection, PyObject* sql)
8285
return rc;
8386
}
8487

85-
int statement_recompile(Statement* self)
88+
int statement_bind_parameter(Statement* self, int pos, PyObject* parameter)
89+
{
90+
int rc = SQLITE_OK;
91+
long longval;
92+
#ifdef HAVE_LONG_LONG
93+
PY_LONG_LONG longlongval;
94+
#endif
95+
const char* buffer;
96+
char* string;
97+
int buflen;
98+
PyObject* stringval;
99+
100+
if (parameter == Py_None) {
101+
rc = sqlite3_bind_null(self->st, pos);
102+
} else if (PyInt_Check(parameter)) {
103+
longval = PyInt_AsLong(parameter);
104+
rc = sqlite3_bind_int64(self->st, pos, (sqlite_int64)longval);
105+
#ifdef HAVE_LONG_LONG
106+
} else if (PyLong_Check(parameter)) {
107+
longlongval = PyLong_AsLongLong(parameter);
108+
/* in the overflow error case, longlongval is -1, and an exception is set */
109+
rc = sqlite3_bind_int64(self->st, pos, (sqlite_int64)longlongval);
110+
#endif
111+
} else if (PyFloat_Check(parameter)) {
112+
rc = sqlite3_bind_double(self->st, pos, PyFloat_AsDouble(parameter));
113+
} else if (PyBuffer_Check(parameter)) {
114+
if (PyObject_AsCharBuffer(parameter, &buffer, &buflen) == 0) {
115+
rc = sqlite3_bind_blob(self->st, pos, buffer, buflen, SQLITE_TRANSIENT);
116+
} else {
117+
PyErr_SetString(PyExc_ValueError, "could not convert BLOB to buffer");
118+
rc = -1;
119+
}
120+
} else if PyString_Check(parameter) {
121+
string = PyString_AsString(parameter);
122+
rc = sqlite3_bind_text(self->st, pos, string, -1, SQLITE_TRANSIENT);
123+
} else if PyUnicode_Check(parameter) {
124+
stringval = PyUnicode_AsUTF8String(parameter);
125+
string = PyString_AsString(stringval);
126+
rc = sqlite3_bind_text(self->st, pos, string, -1, SQLITE_TRANSIENT);
127+
Py_DECREF(stringval);
128+
} else {
129+
rc = -1;
130+
}
131+
132+
return rc;
133+
}
134+
135+
void statement_bind_parameters(Statement* self, PyObject* parameters)
136+
{
137+
PyObject* current_param;
138+
PyObject* adapted;
139+
const char* binding_name;
140+
int i;
141+
int rc;
142+
int num_params_needed;
143+
int num_params;
144+
145+
Py_BEGIN_ALLOW_THREADS
146+
num_params_needed = sqlite3_bind_parameter_count(self->st);
147+
Py_END_ALLOW_THREADS
148+
149+
if (PyDict_Check(parameters)) {
150+
/* parameters passed as dictionary */
151+
for (i = 1; i <= num_params_needed; i++) {
152+
Py_BEGIN_ALLOW_THREADS
153+
binding_name = sqlite3_bind_parameter_name(self->st, i);
154+
Py_END_ALLOW_THREADS
155+
if (!binding_name) {
156+
PyErr_Format(ProgrammingError, "Binding %d has no name, but you supplied a dictionary (which has only names).", i);
157+
return;
158+
}
159+
160+
binding_name++; /* skip first char (the colon) */
161+
current_param = PyDict_GetItemString(parameters, binding_name);
162+
if (!current_param) {
163+
PyErr_Format(ProgrammingError, "You did not supply a value for binding %d.", i);
164+
return;
165+
}
166+
167+
Py_INCREF(current_param);
168+
adapted = microprotocols_adapt(current_param, (PyObject*)&SQLitePrepareProtocolType, NULL);
169+
if (adapted) {
170+
Py_DECREF(current_param);
171+
} else {
172+
PyErr_Clear();
173+
adapted = current_param;
174+
}
175+
176+
rc = statement_bind_parameter(self, i, adapted);
177+
Py_DECREF(adapted);
178+
179+
if (rc != SQLITE_OK) {
180+
PyErr_Format(InterfaceError, "Error binding parameter :%s - probably unsupported type.", binding_name);
181+
return;
182+
}
183+
}
184+
} else {
185+
/* parameters passed as sequence */
186+
num_params = PySequence_Length(parameters);
187+
if (num_params != num_params_needed) {
188+
PyErr_Format(ProgrammingError, "Incorrect number of bindings supplied. The current statement uses %d, and there are %d supplied.",
189+
num_params_needed, num_params);
190+
return;
191+
}
192+
for (i = 0; i < num_params; i++) {
193+
current_param = PySequence_GetItem(parameters, i);
194+
if (!current_param) {
195+
return;
196+
}
197+
adapted = microprotocols_adapt(current_param, (PyObject*)&SQLitePrepareProtocolType, NULL);
198+
199+
if (adapted) {
200+
Py_DECREF(current_param);
201+
} else {
202+
PyErr_Clear();
203+
adapted = current_param;
204+
}
205+
206+
rc = statement_bind_parameter(self, i + 1, adapted);
207+
Py_DECREF(adapted);
208+
209+
if (rc != SQLITE_OK) {
210+
PyErr_Format(InterfaceError, "Error binding parameter %d - probably unsupported type.", i);
211+
return;
212+
}
213+
}
214+
}
215+
}
216+
217+
int statement_recompile(Statement* self, PyObject* params)
86218
{
87219
const char* tail;
88220
int rc;
@@ -98,7 +230,17 @@ int statement_recompile(Statement* self)
98230
&tail);
99231

100232
if (rc == SQLITE_OK) {
233+
/* The efficient sqlite3_transfer_bindings is only available in SQLite
234+
* version 3.2.2 or later. For older SQLite releases, that might not
235+
* even define SQLITE_VERSION_NUMBER, we do it the manual way.
236+
*/
237+
#ifdef SQLITE_VERSION_NUMBER
238+
#if SQLITE_VERSION_NUMBER >= 3002002
101239
(void)sqlite3_transfer_bindings(self->st, new_st);
240+
#endif
241+
#else
242+
statement_bind_parameters(self, params);
243+
#endif
102244

103245
(void)sqlite3_finalize(self->st);
104246
self->st = new_st;

Modules/_sqlite/statement.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,10 @@ extern PyTypeObject StatementType;
4545
int statement_create(Statement* self, Connection* connection, PyObject* sql);
4646
void statement_dealloc(Statement* self);
4747

48-
int statement_recompile(Statement* self);
48+
int statement_bind_parameter(Statement* self, int pos, PyObject* parameter);
49+
void statement_bind_parameters(Statement* self, PyObject* parameters);
50+
51+
int statement_recompile(Statement* self, PyObject* parameters);
4952
int statement_finalize(Statement* self);
5053
int statement_reset(Statement* self);
5154
void statement_mark_dirty(Statement* self);

0 commit comments

Comments
 (0)