summaryrefslogtreecommitdiffstats
path: root/Modules/_sqlite/statement.c
diff options
context:
space:
mode:
authorGerhard Häring <gh@ghaering.de>2008-03-29 00:45:29 (GMT)
committerGerhard Häring <gh@ghaering.de>2008-03-29 00:45:29 (GMT)
commite7ea7451a84636655927da4b9731d2eb37d1cf34 (patch)
tree7862ebdca8d04d799ddeacf4cf74e2a130e376b4 /Modules/_sqlite/statement.c
parentb1b9382d91e4b2e863225179cde4a61f0300a233 (diff)
downloadcpython-e7ea7451a84636655927da4b9731d2eb37d1cf34.zip
cpython-e7ea7451a84636655927da4b9731d2eb37d1cf34.tar.gz
cpython-e7ea7451a84636655927da4b9731d2eb37d1cf34.tar.bz2
Bring sqlite3 module up-to-date with what's now in 2.6. Almost. I intentionally
left out the stuff about creating a connection object from a APSW connection.
Diffstat (limited to 'Modules/_sqlite/statement.c')
-rw-r--r--Modules/_sqlite/statement.c225
1 files changed, 158 insertions, 67 deletions
diff --git a/Modules/_sqlite/statement.c b/Modules/_sqlite/statement.c
index d280a67..66adff3 100644
--- a/Modules/_sqlite/statement.c
+++ b/Modules/_sqlite/statement.c
@@ -1,6 +1,6 @@
/* statement.c - the statement type
*
- * Copyright (C) 2005-2006 Gerhard Häring <gh@ghaering.de>
+ * Copyright (C) 2005-2007 Gerhard Häring <gh@ghaering.de>
*
* This file is part of pysqlite.
*
@@ -40,6 +40,15 @@ typedef enum {
NORMAL
} parse_remaining_sql_state;
+typedef enum {
+ TYPE_LONG,
+ TYPE_FLOAT,
+ TYPE_STRING,
+ TYPE_UNICODE,
+ TYPE_BUFFER,
+ TYPE_UNKNOWN
+} parameter_type;
+
int pysqlite_statement_create(pysqlite_Statement* self, pysqlite_Connection* connection, PyObject* sql)
{
const char* tail;
@@ -77,52 +86,102 @@ int pysqlite_statement_create(pysqlite_Statement* self, pysqlite_Connection* con
return rc;
}
-int pysqlite_statement_bind_parameter(pysqlite_Statement* self, int pos, PyObject* parameter)
+int pysqlite_statement_bind_parameter(pysqlite_Statement* self, int pos, PyObject* parameter, int allow_8bit_chars)
{
int rc = SQLITE_OK;
+ long longval;
#ifdef HAVE_LONG_LONG
PY_LONG_LONG longlongval;
-#else
- long longval;
#endif
const char* buffer;
char* string;
Py_ssize_t buflen;
+ parameter_type paramtype;
+ char* c;
if (parameter == Py_None) {
rc = sqlite3_bind_null(self->st, pos);
-#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);
-#else
+ goto final;
+ }
+
+ if (PyLong_CheckExact(parameter)) {
+ paramtype = TYPE_LONG;
+ } else if (PyFloat_CheckExact(parameter)) {
+ paramtype = TYPE_FLOAT;
+ } else if (PyUnicode_CheckExact(parameter)) {
+ paramtype = TYPE_UNICODE;
} else if (PyLong_Check(parameter)) {
- longval = PyLong_AsLong(parameter);
- /* in the overflow error case, longval is -1, and an exception is set */
- rc = sqlite3_bind_int64(self->st, pos, (sqlite_int64)longval);
-#endif
+ paramtype = TYPE_LONG;
} else if (PyFloat_Check(parameter)) {
- rc = sqlite3_bind_double(self->st, pos, PyFloat_AsDouble(parameter));
- } else if PyUnicode_Check(parameter) {
- string = PyUnicode_AsString(parameter);
-
- rc = sqlite3_bind_text(self->st, pos, string, -1, SQLITE_TRANSIENT);
+ paramtype = TYPE_FLOAT;
+ } else if (PyUnicode_Check(parameter)) {
+ paramtype = TYPE_STRING;
} else if (PyObject_CheckBuffer(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;
- }
+ paramtype = TYPE_BUFFER;
} else {
- rc = -1;
+ paramtype = TYPE_UNKNOWN;
}
+ if (paramtype == TYPE_STRING && !allow_8bit_chars) {
+ string = PyString_AS_STRING(parameter);
+ for (c = string; *c != 0; c++) {
+ if (*c & 0x80) {
+ PyErr_SetString(pysqlite_ProgrammingError, "You must not use 8-bit bytestrings unless you use a text_factory that can interpret 8-bit bytestrings (like text_factory = str). It is highly recommended that you instead just switch your application to Unicode strings.");
+ rc = -1;
+ goto final;
+ }
+ }
+ }
+
+ switch (paramtype) {
+ case TYPE_LONG:
+ /* in the overflow error case, longval/longlongval is -1, and an exception is set */
+#ifdef HAVE_LONG_LONG
+ longlongval = PyLong_AsLongLong(parameter);
+ rc = sqlite3_bind_int64(self->st, pos, (sqlite_int64)longlongval);
+#else
+ rc = sqlite3_bind_int64(self->st, pos, (sqlite_int64)longval);
+#endif
+ break;
+ case TYPE_FLOAT:
+ rc = sqlite3_bind_double(self->st, pos, PyFloat_AsDouble(parameter));
+ break;
+ case TYPE_UNICODE:
+ string = PyUnicode_AsString(parameter);
+ rc = sqlite3_bind_text(self->st, pos, string, -1, SQLITE_TRANSIENT);
+ break;
+ case TYPE_BUFFER:
+ 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;
+ }
+ break;
+ case TYPE_UNKNOWN:
+ rc = -1;
+ }
+
+final:
return rc;
}
-void pysqlite_statement_bind_parameters(pysqlite_Statement* self, PyObject* parameters)
+/* returns 0 if the object is one of Python's internal ones that don't need to be adapted */
+static int _need_adapt(PyObject* obj)
+{
+ if (pysqlite_BaseTypeAdapted) {
+ return 1;
+ }
+
+ if (PyLong_CheckExact(obj) || PyFloat_CheckExact(obj)
+ || PyUnicode_CheckExact(obj) || PyBytes_CheckExact(obj)) {
+ return 0;
+ } else {
+ return 1;
+ }
+}
+
+void pysqlite_statement_bind_parameters(pysqlite_Statement* self, PyObject* parameters, int allow_8bit_chars)
{
PyObject* current_param;
PyObject* adapted;
@@ -136,7 +195,57 @@ void pysqlite_statement_bind_parameters(pysqlite_Statement* self, PyObject* para
num_params_needed = sqlite3_bind_parameter_count(self->st);
Py_END_ALLOW_THREADS
- if (PyDict_Check(parameters)) {
+ if (PyTuple_CheckExact(parameters) || PyList_CheckExact(parameters) || (!PyDict_Check(parameters) && PySequence_Check(parameters))) {
+ /* parameters passed as sequence */
+ if (PyTuple_CheckExact(parameters)) {
+ num_params = PyTuple_GET_SIZE(parameters);
+ } else if (PyList_CheckExact(parameters)) {
+ num_params = PyList_GET_SIZE(parameters);
+ } else {
+ num_params = PySequence_Size(parameters);
+ }
+ if (num_params != num_params_needed) {
+ PyErr_Format(pysqlite_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++) {
+ if (PyTuple_CheckExact(parameters)) {
+ current_param = PyTuple_GET_ITEM(parameters, i);
+ Py_XINCREF(current_param);
+ } else if (PyList_CheckExact(parameters)) {
+ current_param = PyList_GET_ITEM(parameters, i);
+ Py_XINCREF(current_param);
+ } else {
+ current_param = PySequence_GetItem(parameters, i);
+ }
+ if (!current_param) {
+ return;
+ }
+
+ if (!_need_adapt(current_param)) {
+ adapted = current_param;
+ } else {
+ adapted = microprotocols_adapt(current_param, (PyObject*)&pysqlite_PrepareProtocolType, NULL);
+ if (adapted) {
+ Py_DECREF(current_param);
+ } else {
+ PyErr_Clear();
+ adapted = current_param;
+ }
+ }
+
+ rc = pysqlite_statement_bind_parameter(self, i + 1, adapted, allow_8bit_chars);
+ Py_DECREF(adapted);
+
+ if (rc != SQLITE_OK) {
+ if (!PyErr_Occurred()) {
+ PyErr_Format(pysqlite_InterfaceError, "Error binding parameter %d - probably unsupported type.", i);
+ }
+ return;
+ }
+ }
+ } else if (PyDict_Check(parameters)) {
/* parameters passed as dictionary */
for (i = 1; i <= num_params_needed; i++) {
Py_BEGIN_ALLOW_THREADS
@@ -148,59 +257,41 @@ void pysqlite_statement_bind_parameters(pysqlite_Statement* self, PyObject* para
}
binding_name++; /* skip first char (the colon) */
- current_param = PyDict_GetItemString(parameters, binding_name);
+ if (PyDict_CheckExact(parameters)) {
+ current_param = PyDict_GetItemString(parameters, binding_name);
+ Py_XINCREF(current_param);
+ } else {
+ current_param = PyMapping_GetItemString(parameters, (char*)binding_name);
+ }
if (!current_param) {
PyErr_Format(pysqlite_ProgrammingError, "You did not supply a value for binding %d.", i);
return;
}
- Py_INCREF(current_param);
- adapted = microprotocols_adapt(current_param, (PyObject*)&pysqlite_PrepareProtocolType, NULL);
- if (adapted) {
- Py_DECREF(current_param);
- } else {
- PyErr_Clear();
+ if (!_need_adapt(current_param)) {
adapted = current_param;
+ } else {
+ adapted = microprotocols_adapt(current_param, (PyObject*)&pysqlite_PrepareProtocolType, NULL);
+ if (adapted) {
+ Py_DECREF(current_param);
+ } else {
+ PyErr_Clear();
+ adapted = current_param;
+ }
}
- rc = pysqlite_statement_bind_parameter(self, i, adapted);
+ rc = pysqlite_statement_bind_parameter(self, i, adapted, allow_8bit_chars);
Py_DECREF(adapted);
if (rc != SQLITE_OK) {
- PyErr_Format(pysqlite_InterfaceError, "Error binding parameter :%s - probably unsupported type.", binding_name);
+ if (!PyErr_Occurred()) {
+ PyErr_Format(pysqlite_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(pysqlite_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*)&pysqlite_PrepareProtocolType, NULL);
-
- if (adapted) {
- Py_DECREF(current_param);
- } else {
- PyErr_Clear();
- adapted = current_param;
- }
-
- rc = pysqlite_statement_bind_parameter(self, i + 1, adapted);
- Py_DECREF(adapted);
-
- if (rc != SQLITE_OK) {
- PyErr_Format(pysqlite_InterfaceError, "Error binding parameter %d - probably unsupported type.", i);
- return;
- }
- }
+ PyErr_SetString(PyExc_ValueError, "parameters are of unsupported type");
}
}
@@ -400,7 +491,7 @@ PyTypeObject pysqlite_StatementType = {
0, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
- Py_TPFLAGS_DEFAULT, /* tp_flags */
+ Py_TPFLAGS_DEFAULT, /* tp_flags */
0, /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */