From e0fa7978fa94e35b7a0f59f17b458bb2826c9ad0 Mon Sep 17 00:00:00 2001 From: bRong Njam Date: Fri, 9 Oct 2026 01:30:08 +0800 Subject: [PATCH 1/2] fix(numeric): preserve opaque decimal root column names --- docs/mo-exact-decimal-import.md | 3 +++ src/numeric/decimal_import.cpp | 5 ++++ test/cpp/embedding/test_decimal_import.cpp | 29 ++++++++++++++++++++++ 3 files changed, 37 insertions(+) diff --git a/docs/mo-exact-decimal-import.md b/docs/mo-exact-decimal-import.md index b4d5148660..40259fea18 100644 --- a/docs/mo-exact-decimal-import.md +++ b/docs/mo-exact-decimal-import.md @@ -18,6 +18,9 @@ The first type owner is the validated import descriptor. Ordinary DuckDB decimal inference cannot substitute a narrower carrier. Decimal64/128 use tagged BIGINT/HUGEINT DuckDB carriers; Decimal256 uses the signed-high/unsigned low limb STRUCT introduced by #25. Sirius retains a distinct MO decimal type. +The scoped importer marks canonical exact-decimal carriers as opaque when +assigning SQL root names. Decimal256's private limbs consume no additional +headings; ordinary SQL STRUCT fields retain their usual flattened names. The private alias records the descriptor and is validated against the complete physical carrier on conversion. It is internal binding metadata, not a new diff --git a/src/numeric/decimal_import.cpp b/src/numeric/decimal_import.cpp index 20028c4d49..c2b05e6a02 100644 --- a/src/numeric/decimal_import.cpp +++ b/src/numeric/decimal_import.cpp @@ -63,6 +63,11 @@ class importer final : public duckdb::SubstraitExtensionHandler { public: explicit importer(std::vector anchors) : anchors_(std::move(anchors)) {} + bool IsOpaqueType(duckdb::LogicalType const& type) const override + { + auto exact = from_duckdb_type(type); + return exact && exact->is_mo_decimal(); + } bool Handles(duckdb::SubstraitExtensionIdentity const& identity) const override { return identity.urn == extension_uri; diff --git a/test/cpp/embedding/test_decimal_import.cpp b/test/cpp/embedding/test_decimal_import.cpp index dee0756989..d706604a16 100644 --- a/test/cpp/embedding/test_decimal_import.cpp +++ b/test/cpp/embedding/test_decimal_import.cpp @@ -10,11 +10,40 @@ #include "numeric/exact_decimal.hpp" #include +#include #include #include using namespace sirius; +TEST_CASE("MO opaque carriers preserve following SQL root columns", "[decimal_import]") +{ + decimal_fixture::importer fixture; + for (uint16_t bits : {64, 128, 256}) { + mo_decimal::decimal_type input{bits, 9, 2}, output{bits, 15, 2}; + auto plan = decimal_fixture::plan( + "mo_decimal_cast", decimal_fixture::type(output), {decimal_fixture::literal(input, 125)}); + auto root = plan.mutable_relations(0)->mutable_root(); + root->add_names("after"); + auto project = root->mutable_input()->mutable_project(); + project->mutable_common()->mutable_emit()->add_output_mapping(2); + project->add_expressions()->mutable_literal()->set_i64(42); + auto bytes = plan.SerializeAsString(); + auto handler = mo_decimal::make_import_handler(bytes); + CHECK(handler->IsOpaqueType(to_duckdb(logical_type::make_mo_decimal(output, false)))); + CHECK_FALSE( + handler->IsOpaqueType(duckdb::LogicalType::STRUCT({{"v", duckdb::LogicalType::BIGINT}}))); + duckdb::SubstraitToDuckDB converter(fixture.connection.context, bytes, false, false, handler); + auto relation = converter.TransformPlan(); + auto const& columns = relation->Columns(); + REQUIRE(columns.size() == 2); + CHECK(columns[0].GetName() == "exact"); + CHECK(columns[1].GetName() == "after"); + CHECK(from_duckdb(columns[0].GetType()) == logical_type::make_mo_decimal(output, false)); + CHECK(columns[1].GetType() == duckdb::LogicalType::BIGINT); + } +} + TEST_CASE("MO import carriers retain width precision scale and nullability", "[decimal_import]") { for (uint16_t bits : {64, 128, 256}) { From 433cadd43a10442b0825a23234fb6d859207e9d5 Mon Sep 17 00:00:00 2001 From: bRong Njam Date: Fri, 9 Oct 2026 02:39:08 +0800 Subject: [PATCH 2/2] build(numeric): pin merged opaque-carrier importer fix --- substrait | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrait b/substrait index 95d9ce8d78..99c7ca3b6f 160000 --- a/substrait +++ b/substrait @@ -1 +1 @@ -Subproject commit 95d9ce8d78490db3991ab6145653716aa3ec42c9 +Subproject commit 99c7ca3b6f8f3159239e119ed2982d42f98c4690