diff --git a/include/quack/quack_types.hpp b/include/quack/quack_types.hpp index 05f38603..62236313 100644 --- a/include/quack/quack_types.hpp +++ b/include/quack/quack_types.hpp @@ -8,7 +8,7 @@ extern "C" { } namespace quack { -duckdb::LogicalType ConvertPostgresToDuckColumnType(Oid type); +duckdb::LogicalType ConvertPostgresToDuckColumnType(Oid type, int32_t typmod); void ConvertPostgresToDuckValue(Datum value, duckdb::Vector &result, idx_t offset); void ConvertDuckToPostgresValue(TupleTableSlot *slot, duckdb::Value &value, idx_t col); void InsertTupleIntoChunk(duckdb::DataChunk &output, TupleDesc tuple, HeapTupleData *slot, idx_t offset); diff --git a/src/quack_heap_scan.cpp b/src/quack_heap_scan.cpp index 09d06065..65a13cf2 100644 --- a/src/quack_heap_scan.cpp +++ b/src/quack_heap_scan.cpp @@ -30,7 +30,7 @@ PostgresHeapScanFunctionData::~PostgresHeapScanFunctionData() { PostgresHeapScanGlobalState::PostgresHeapScanGlobalState(PostgresHeapSeqScan &relation) { relation.InitParallelScanState(); - elog(DEBUG3, "-- (DuckDB/PostgresHeapScanGlobalState) Running %lu threads -- ", MaxThreads()); + elog(DEBUG3, "-- (DuckDB/PostgresHeapScanGlobalState) Running %llu threads -- ", MaxThreads()); } PostgresHeapScanGlobalState::~PostgresHeapScanGlobalState() { @@ -79,8 +79,9 @@ PostgresHeapScanFunction::PostgresHeapBind(duckdb::ClientContext &context, duckd for (int i = 0; i < tupleDesc->natts; i++) { Form_pg_attribute attr = &tupleDesc->attrs[i]; Oid type_oid = attr->atttypid; + auto typmod = attr->atttypmod; auto col_name = duckdb::string(NameStr(attr->attname)); - auto duck_type = ConvertPostgresToDuckColumnType(type_oid); + auto duck_type = ConvertPostgresToDuckColumnType(type_oid, typmod); return_types.push_back(duck_type); names.push_back(col_name); /* Log column name and type */ diff --git a/src/quack_types.cpp b/src/quack_types.cpp index 11c9ac34..b80c93ca 100644 --- a/src/quack_types.cpp +++ b/src/quack_types.cpp @@ -1,4 +1,5 @@ #include "duckdb.hpp" +#include "duckdb/common/extra_type_info.hpp" extern "C" { #include "postgres.h" @@ -71,8 +72,26 @@ ConvertDuckToPostgresValue(TupleTableSlot *slot, duckdb::Value &value, idx_t col } } +static inline int +numeric_typmod_precision(int32 typmod) +{ + return ((typmod - VARHDRSZ) >> 16) & 0xffff; +} + +static inline int +numeric_typmod_scale(int32 typmod) +{ + return (((typmod - VARHDRSZ) & 0x7ff) ^ 1024) - 1024; +} + +struct NumericAsDouble : public duckdb::ExtraTypeInfo { +// Dummy struct to indicate at conversion that the source is a Numeric +public: + NumericAsDouble() : ExtraTypeInfo(duckdb::ExtraTypeInfoType::INVALID_TYPE_INFO) {} +}; + duckdb::LogicalType -ConvertPostgresToDuckColumnType(Oid type) { +ConvertPostgresToDuckColumnType(Oid type, int32_t typmod) { switch (type) { case BOOLOID: return duckdb::LogicalTypeId::BOOLEAN; @@ -92,8 +111,19 @@ ConvertPostgresToDuckColumnType(Oid type) { return duckdb::LogicalTypeId::DATE; case TIMESTAMPOID: return duckdb::LogicalTypeId::TIMESTAMP; + case FLOAT8OID: + return duckdb::LogicalTypeId::DOUBLE; + case NUMERICOID: { + if (typmod == -1) { + auto extra_type_info = duckdb::make_shared(); + return duckdb::LogicalType(duckdb::LogicalTypeId::DOUBLE, std::move(extra_type_info)); + } + auto precision = numeric_typmod_precision(typmod); + auto scale = numeric_typmod_scale(typmod); + return duckdb::LogicalType::DECIMAL(precision, scale); + } default: - elog(ERROR, "Unsupported quack type: %d", type); + elog(ERROR, "Unsupported quack (Postgres) type: %d", type); } } @@ -116,8 +146,8 @@ AppendString(duckdb::Vector &result, Datum value, idx_t offset) { void ConvertPostgresToDuckValue(Datum value, duckdb::Vector &result, idx_t offset) { - - switch (result.GetType().id()) { + auto &type = result.GetType(); + switch (type.id()) { case duckdb::LogicalTypeId::BOOLEAN: Append(result, DatumGetBool(value), offset); break; @@ -143,8 +173,18 @@ ConvertPostgresToDuckValue(Datum value, duckdb::Vector &result, idx_t offset) { Append(result, duckdb::dtime_t(static_cast(value + QUACK_DUCK_TIMESTAMP_OFFSET)), offset); break; + case duckdb::LogicalTypeId::DOUBLE: { + auto aux_info = type.GetAuxInfoShrPtr(); + if (aux_info && dynamic_cast(aux_info.get())) { + elog(ERROR, "NUMERIC AS DOUBLE"); + } + Append(result, DatumGetFloat8(value), offset); + break; + } + case duckdb::LogicalTypeId::DECIMAL: + elog(ERROR, "DECIMAL TYPE"); default: - elog(ERROR, "Unsupported quack type: %d", static_cast(result.GetType().id())); + elog(ERROR, "Unsupported quack (DuckDB) type: %d", static_cast(result.GetType().id())); break; } }