Add column decltype to cursor description.

This commit is contained in:
Charles Leifer 2023-01-10 08:26:44 -06:00
parent 3f8b297958
commit 61e9937224
2 changed files with 49 additions and 3 deletions

View file

@ -219,6 +219,15 @@ _pysqlite_build_column_name(pysqlite_Cursor *self, const char *colname)
return PyUnicode_FromStringAndSize(colname, len); return PyUnicode_FromStringAndSize(colname, len);
} }
static PyObject *
_pysqlite_build_column_decltype(pysqlite_Cursor *self, const char *decltype)
{
if (!decltype) {
Py_RETURN_NONE;
}
return PyUnicode_FromStringAndSize(decltype, strlen(decltype));
}
/* /*
* Returns a row from the currently active SQLite statement * Returns a row from the currently active SQLite statement
* *
@ -378,6 +387,7 @@ _pysqlite_query_execute(pysqlite_Cursor* self, int multiple, PyObject* args)
PyObject* result; PyObject* result;
int numcols; int numcols;
PyObject* column_name; PyObject* column_name;
PyObject* column_decltype;
PyObject* second_argument = NULL; PyObject* second_argument = NULL;
sqlite_int64 lastrowid; sqlite_int64 lastrowid;
@ -541,6 +551,7 @@ _pysqlite_query_execute(pysqlite_Cursor* self, int multiple, PyObject* args)
} }
for (i = 0; i < numcols; i++) { for (i = 0; i < numcols; i++) {
const char *colname; const char *colname;
const char *decltype;
colname = sqlite3_column_name(self->statement->st, i); colname = sqlite3_column_name(self->statement->st, i);
if (colname == NULL) { if (colname == NULL) {
PyErr_NoMemory(); PyErr_NoMemory();
@ -550,10 +561,18 @@ _pysqlite_query_execute(pysqlite_Cursor* self, int multiple, PyObject* args)
if (!column_name) { if (!column_name) {
goto error; goto error;
} }
PyObject *descriptor = PyTuple_Pack(7, column_name, decltype = sqlite3_column_decltype(self->statement->st, i);
Py_None, Py_None, Py_None, column_decltype = _pysqlite_build_column_decltype(self, decltype);
Py_None, Py_None, Py_None); if (!column_decltype) {
Py_DECREF(column_name); Py_DECREF(column_name);
goto error;
}
PyObject *descriptor = PyTuple_Pack(7, column_name, column_decltype,
Py_None, Py_None, Py_None,
Py_None, Py_None);
Py_DECREF(column_name);
Py_DECREF(column_decltype);
if (descriptor == NULL) { if (descriptor == NULL) {
goto error; goto error;
} }

View file

@ -1017,6 +1017,32 @@ class ClosedCurTests(unittest.TestCase):
method(*params) method(*params)
class SqliteColumnTypeTests(unittest.TestCase):
def setUp(self):
self.cx = sqlite.connect(':memory:')
self.cx.execute('create table test(a text, b datetime)')
self.cx.execute('create view test_view as select * from test')
def CheckDeclTypes(self):
curs = self.cx.execute('select * from test')
self.assertEqual(curs.description, (
('a', 'TEXT', None, None, None, None, None),
('b', 'datetime', None, None, None, None, None),
))
curs = self.cx.execute('select * from test_view')
self.assertEqual(curs.description, (
('a', 'TEXT', None, None, None, None, None),
('b', 'datetime', None, None, None, None, None),
))
# Expressions return NULL decltype, reported as None.
curs = self.cx.execute('select b + b as c from test_view')
self.assertEqual(curs.description, (
('c', None, None, None, None, None, None),
))
class SqliteOnConflictTests(unittest.TestCase): class SqliteOnConflictTests(unittest.TestCase):
""" """
Tests for SQLite's "insert on conflict" feature. Tests for SQLite's "insert on conflict" feature.
@ -1181,6 +1207,7 @@ def suite():
ext_suite = unittest.makeSuite(ExtensionTests, "Check") ext_suite = unittest.makeSuite(ExtensionTests, "Check")
closed_con_suite = unittest.makeSuite(ClosedConTests, "Check") closed_con_suite = unittest.makeSuite(ClosedConTests, "Check")
closed_cur_suite = unittest.makeSuite(ClosedCurTests, "Check") closed_cur_suite = unittest.makeSuite(ClosedCurTests, "Check")
columntypes_suite = unittest.makeSuite(SqliteColumnTypeTests, "Check")
on_conflict_suite = unittest.makeSuite(SqliteOnConflictTests, "Check") on_conflict_suite = unittest.makeSuite(SqliteOnConflictTests, "Check")
blob_suite = unittest.makeSuite(BlobTests, "Check") blob_suite = unittest.makeSuite(BlobTests, "Check")
closed_blob_suite = unittest.makeSuite(ClosedBlobTests, "Check") closed_blob_suite = unittest.makeSuite(ClosedBlobTests, "Check")
@ -1188,7 +1215,7 @@ def suite():
return unittest.TestSuite(( return unittest.TestSuite((
module_suite, connection_suite, cursor_suite, thread_suite, module_suite, connection_suite, cursor_suite, thread_suite,
constructor_suite, ext_suite, closed_con_suite, closed_cur_suite, constructor_suite, ext_suite, closed_con_suite, closed_cur_suite,
on_conflict_suite, blob_suite, closed_blob_suite, columntypes_suite, on_conflict_suite, blob_suite, closed_blob_suite,
blob_context_manager_suite, blob_context_manager_suite,
)) ))