From 2936ef3f5ba4911a99971cf7dfa8a1a5ec7c9f36 Mon Sep 17 00:00:00 2001 From: Elliana Date: Thu, 8 Jul 2021 14:20:16 +0800 Subject: [PATCH] Populate type_code --- .gitignore | 3 ++ tools/pythonpkg/src/pyresult.cpp | 47 ++++++++++++++++++++++- tools/pythonpkg/tests/api/test_dbapi10.py | 25 ++++++++++-- 3 files changed, 71 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index ca0d0dfdd46a..06417654b1cc 100644 --- a/.gitignore +++ b/.gitignore @@ -335,3 +335,6 @@ tools/pythonpkg/tests/userdata1.parquet # node tests __nvm +*.vcxproj* +*.cmake +*.sln \ No newline at end of file diff --git a/tools/pythonpkg/src/pyresult.cpp b/tools/pythonpkg/src/pyresult.cpp index 3bd42da5ad07..7ada0fd8c5f7 100644 --- a/tools/pythonpkg/src/pyresult.cpp +++ b/tools/pythonpkg/src/pyresult.cpp @@ -264,12 +264,57 @@ py::object DuckDBPyResult::FetchArrowTable() { return from_batches_func(batches, schema_obj); } +py::str GetTypeToPython(const LogicalType &type) { + switch (type.id()) { + case LogicalTypeId::BOOLEAN: + return py::str("bool"); + case LogicalTypeId::TINYINT: + case LogicalTypeId::SMALLINT: + case LogicalTypeId::INTEGER: + case LogicalTypeId::BIGINT: + case LogicalTypeId::UTINYINT: + case LogicalTypeId::USMALLINT: + case LogicalTypeId::UINTEGER: + case LogicalTypeId::UBIGINT: + case LogicalTypeId::HUGEINT: + case LogicalTypeId::FLOAT: + case LogicalTypeId::DOUBLE: + case LogicalTypeId::DECIMAL: { + return py::str("NUMBER"); + } + case LogicalTypeId::VARCHAR: + return py::str("STRING"); + case LogicalTypeId::BLOB: + return py::str("BINARY"); + case LogicalTypeId::TIMESTAMP: + case LogicalTypeId::TIMESTAMP_MS: + case LogicalTypeId::TIMESTAMP_NS: + case LogicalTypeId::TIMESTAMP_SEC: { + return py::str("DATETIME"); + } + case LogicalTypeId::TIME: { + return py::str("Time"); + } + case LogicalTypeId::DATE: { + return py::str("Date"); + } + case LogicalTypeId::MAP: + case LogicalTypeId::STRUCT: + return py::str("dict"); + case LogicalTypeId::LIST: { + return py::str("list"); + } + default: + throw std::runtime_error("unsupported type: " + type.ToString()); + } +} + py::list DuckDBPyResult::Description() { py::list desc(result->names.size()); for (idx_t col_idx = 0; col_idx < result->names.size(); col_idx++) { py::tuple col_desc(7); col_desc[0] = py::str(result->names[col_idx]); - col_desc[1] = py::none(); + col_desc[1] = GetTypeToPython(result->types[col_idx]); col_desc[2] = py::none(); col_desc[3] = py::none(); col_desc[4] = py::none(); diff --git a/tools/pythonpkg/tests/api/test_dbapi10.py b/tools/pythonpkg/tests/api/test_dbapi10.py index 06049a92efbd..826cef9d1346 100644 --- a/tools/pythonpkg/tests/api/test_dbapi10.py +++ b/tools/pythonpkg/tests/api/test_dbapi10.py @@ -1,9 +1,28 @@ # cursor description +from datetime import datetime, date +from pytest import mark + class TestCursorDescription(object): - def test_description(self, duckdb_cursor): - description = duckdb_cursor.execute("SELECT * FROM integers").description - assert description == [('i', None, None, None, None, None, None)] + @mark.parametrize( + "query,column_name,string_type,real_type", + [ + ["SELECT * FROM integers", "i", "NUMBER", int], + ["SELECT * FROM timestamps", "t", "DATETIME", datetime], + ["SELECT DATE '1992-09-20';", "CAST(1992-09-20 AS DATE)", "Date", date], + ["SELECT '\\xAA'::BLOB;", "\\xAA", "BINARY", bytes], + ["SELECT {'x': 1, 'y': 2, 'z': 3}", "struct_pack(1, 2, 3)", "dict", dict], + ["SELECT [1, 2, 3]", "list_value(1, 2, 3)", "list", list], + ], + ) + def test_description( + self, query, column_name, string_type, real_type, duckdb_cursor + ): + duckdb_cursor.execute(query) + assert duckdb_cursor.description == [ + (column_name, string_type, None, None, None, None, None) + ] + assert isinstance(duckdb_cursor.fetchone()[0], real_type) def test_none_description(self, duckdb_empty_cursor): assert duckdb_empty_cursor.description is None