Thanks to visit codestin.com
Credit goes to github.com

Skip to content

gh-89022: Improve sqlite3 exceptions related to binding params and API misuse #91572

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
May 4, 2022
2 changes: 1 addition & 1 deletion Lib/test/test_sqlite3/test_dbapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -743,7 +743,7 @@ def test_execute_arg_string_with_zero_byte(self):
self.assertEqual(row[0], "Hu\x00go")

def test_execute_non_iterable(self):
with self.assertRaises(ValueError) as cm:
with self.assertRaises(sqlite.ProgrammingError) as cm:
self.cu.execute("insert into test(id) values (?)", 42)
self.assertEqual(str(cm.exception), 'parameters are of unsupported type')

Expand Down
8 changes: 4 additions & 4 deletions Lib/test/test_sqlite3/test_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -255,9 +255,9 @@ def test_foo(self):

def test_error_in_conform(self):
val = DeclTypesTests.BadConform(TypeError)
with self.assertRaises(sqlite.InterfaceError):
with self.assertRaises(sqlite.ProgrammingError):
self.cur.execute("insert into test(bad) values (?)", (val,))
with self.assertRaises(sqlite.InterfaceError):
with self.assertRaises(sqlite.ProgrammingError):
self.cur.execute("insert into test(bad) values (:val)", {"val": val})

val = DeclTypesTests.BadConform(KeyboardInterrupt)
Expand All @@ -269,13 +269,13 @@ def test_error_in_conform(self):
def test_unsupported_seq(self):
class Bar: pass
val = Bar()
with self.assertRaises(sqlite.InterfaceError):
with self.assertRaises(sqlite.ProgrammingError):
self.cur.execute("insert into test(f) values (?)", (val,))

def test_unsupported_dict(self):
class Bar: pass
val = Bar()
with self.assertRaises(sqlite.InterfaceError):
with self.assertRaises(sqlite.ProgrammingError):
self.cur.execute("insert into test(f) values (:val)", {"val": val})

def test_blob(self):
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
In :mod:`sqlite3`, ``SQLITE_MISUSE`` result codes are now mapped to
:exc:`~sqlite3.InterfaceError` instead of :exc:`~sqlite3.ProgrammingError`.
Also, more accurate exceptions are raised when binding parameters fail.
Patch by Erlend E. Aasland.
33 changes: 19 additions & 14 deletions Modules/_sqlite/cursor.c
Original file line number Diff line number Diff line change
Expand Up @@ -516,7 +516,8 @@ stmt_step(sqlite3_stmt *statement)
}

static int
bind_param(pysqlite_Statement *self, int pos, PyObject *parameter)
bind_param(pysqlite_state *state, pysqlite_Statement *self, int pos,
PyObject *parameter)
{
int rc = SQLITE_OK;
const char *string;
Expand Down Expand Up @@ -592,6 +593,9 @@ bind_param(pysqlite_Statement *self, int pos, PyObject *parameter)
break;
}
case TYPE_UNKNOWN:
PyErr_Format(state->ProgrammingError,
"Error binding parameter %d: type '%s' is not supported",
pos, Py_TYPE(parameter)->tp_name);
rc = -1;
}

Expand Down Expand Up @@ -677,15 +681,15 @@ bind_parameters(pysqlite_state *state, pysqlite_Statement *self,
}
}

rc = bind_param(self, i + 1, adapted);
rc = bind_param(state, self, i + 1, adapted);
Py_DECREF(adapted);

if (rc != SQLITE_OK) {
if (!PyErr_Occurred()) {
PyErr_Format(state->InterfaceError,
"Error binding parameter %d - "
"probably unsupported type.", i);
}
PyObject *exc, *val, *tb;
PyErr_Fetch(&exc, &val, &tb);
sqlite3 *db = sqlite3_db_handle(self->st);
_pysqlite_seterror(state, db);
_PyErr_ChainExceptions(exc, val, tb);
return;
}
}
Expand Down Expand Up @@ -737,20 +741,21 @@ bind_parameters(pysqlite_state *state, pysqlite_Statement *self,
}
}

rc = bind_param(self, i, adapted);
rc = bind_param(state, self, i, adapted);
Py_DECREF(adapted);

if (rc != SQLITE_OK) {
if (!PyErr_Occurred()) {
PyErr_Format(state->InterfaceError,
"Error binding parameter :%s - "
"probably unsupported type.", binding_name);
}
PyObject *exc, *val, *tb;
PyErr_Fetch(&exc, &val, &tb);
sqlite3 *db = sqlite3_db_handle(self->st);
_pysqlite_seterror(state, db);
_PyErr_ChainExceptions(exc, val, tb);
return;
}
}
} else {
PyErr_SetString(PyExc_ValueError, "parameters are of unsupported type");
PyErr_SetString(state->ProgrammingError,
"parameters are of unsupported type");
}
}

Expand Down
1 change: 0 additions & 1 deletion Modules/_sqlite/util.c
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,6 @@ get_exception_class(pysqlite_state *state, int errorcode)
case SQLITE_MISMATCH:
return state->IntegrityError;
case SQLITE_MISUSE:
return state->ProgrammingError;
case SQLITE_RANGE:
return state->InterfaceError;
default:
Expand Down