Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions docs/mo-exact-decimal-import.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
5 changes: 5 additions & 0 deletions src/numeric/decimal_import.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,11 @@ class importer final : public duckdb::SubstraitExtensionHandler {

public:
explicit importer(std::vector<uint32_t> 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;
Expand Down
2 changes: 1 addition & 1 deletion substrait
29 changes: 29 additions & 0 deletions test/cpp/embedding/test_decimal_import.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,40 @@
#include "numeric/exact_decimal.hpp"

#include <catch.hpp>
#include <duckdb/main/relation.hpp>
#include <duckdb/planner/expression/bound_cast_expression.hpp>
#include <duckdb/planner/expression/bound_constant_expression.hpp>

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}) {
Expand Down
Loading