From 5d2f6aaa0f3456627df8a930cc45bef003dbbe38 Mon Sep 17 00:00:00 2001
From: David Li
Date: Tue, 3 Sep 2024 01:06:07 -0400
Subject: [PATCH] feat(c/driver/postgresql): add `arrow.opaque` type metadata
Fixes #2099.
---
c/driver/postgresql/postgres_type.h | 20 ++++++++++++++++++++
c/driver/postgresql/postgres_type_test.cc | 8 ++++++++
docs/source/driver/postgresql.rst | 17 +++++++++++++++++
3 files changed, 45 insertions(+)
diff --git a/c/driver/postgresql/postgres_type.h b/c/driver/postgresql/postgres_type.h
index 02748cf91e..df59b113ed 100644
--- a/c/driver/postgresql/postgres_type.h
+++ b/c/driver/postgresql/postgres_type.h
@@ -312,6 +312,9 @@ class PostgresType {
std::vector children_;
static constexpr const char* kPostgresTypeKey = "ADBC:postgresql:typname";
+ static constexpr const char* kExtensionName = "ARROW:extension:name";
+ static constexpr const char* kOpaqueExtensionName = "arrow.opaque";
+ static constexpr const char* kExtensionMetadata = "ARROW:extension:metadata";
ArrowErrorCode AddPostgresTypeMetadata(ArrowSchema* schema) const {
// the typname_ may not always be set: an instance of this class can be
@@ -322,8 +325,25 @@ class PostgresType {
nanoarrow::UniqueBuffer buffer;
ArrowMetadataBuilderInit(buffer.get(), nullptr);
+ // TODO(lidavidm): we have deprecated this in favor of arrow.opaque,
+ // remove once we feel enough time has passed
NANOARROW_RETURN_NOT_OK(ArrowMetadataBuilderAppend(
buffer.get(), ArrowCharView(kPostgresTypeKey), ArrowCharView(typname)));
+
+ // Add the Opaque extension type metadata
+ std::string metadata = R"({"type_name": ")";
+ metadata += typname;
+ metadata += R"(", "vendor_name": "PostgreSQL"})";
+ NANOARROW_RETURN_NOT_OK(
+ ArrowMetadataBuilderAppend(buffer.get(), ArrowCharView(kExtensionName),
+ ArrowCharView(kOpaqueExtensionName)));
+ NANOARROW_RETURN_NOT_OK(
+ ArrowMetadataBuilderAppend(buffer.get(), ArrowCharView(kExtensionMetadata),
+ ArrowStringView{
+ metadata.c_str(),
+ static_cast(metadata.size()),
+ }));
+
NANOARROW_RETURN_NOT_OK(
ArrowSchemaSetMetadata(schema, reinterpret_cast(buffer->data)));
diff --git a/c/driver/postgresql/postgres_type_test.cc b/c/driver/postgresql/postgres_type_test.cc
index 9d6152f27f..79bd8d5905 100644
--- a/c/driver/postgresql/postgres_type_test.cc
+++ b/c/driver/postgresql/postgres_type_test.cc
@@ -174,6 +174,14 @@ TEST(PostgresTypeTest, PostgresTypeSetSchema) {
&typnameMetadataValue);
EXPECT_EQ(std::string(typnameMetadataValue.data, typnameMetadataValue.size_bytes),
"numeric");
+ ArrowMetadataGetValue(schema->metadata, ArrowCharView("ARROW:extension:name"),
+ &typnameMetadataValue);
+ EXPECT_EQ(std::string(typnameMetadataValue.data, typnameMetadataValue.size_bytes),
+ "arrow.opaque");
+ ArrowMetadataGetValue(schema->metadata, ArrowCharView("ARROW:extension:metadata"),
+ &typnameMetadataValue);
+ EXPECT_EQ(std::string(typnameMetadataValue.data, typnameMetadataValue.size_bytes),
+ R"({"type_name": "numeric", "vendor_name": "PostgreSQL"})");
schema.reset();
ArrowSchemaInit(schema.get());
diff --git a/docs/source/driver/postgresql.rst b/docs/source/driver/postgresql.rst
index 2f67183c8b..5c9d69bd93 100644
--- a/docs/source/driver/postgresql.rst
+++ b/docs/source/driver/postgresql.rst
@@ -329,6 +329,23 @@ being read or written.
overflow/underflow; an error will be returned if this would be
the case.
+Unknown Types
+~~~~~~~~~~~~~
+
+Types without direct Arrow equivalents can still be returned by the driver.
+In this case, the Arrow type will be binary, and the contents will be the raw
+bytes as provided by the PostgreSQL wire protocol.
+
+For Arrow implementations that support the :external:doc:`Opaque canonical
+extension type `, the extension type metadata is
+also always present. This helps differentiate when the driver intentionally
+returned a binary column from when it returned a binary column as a fallback.
+
+.. warning:: Currently, the driver also attaches a metadata key named
+ ``ADBC:posgresql:typname`` to the schema field of the unknown
+ column, but this has been deprecated in favor of the Opaque type
+ and you should not rely on this key continuing to exist.
+
Software Versions
=================