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 =================