This is an automated email from the ASF dual-hosted git repository.

paleolimbot pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/arrow-adbc.git


The following commit(s) were added to refs/heads/main by this push:
     new a2a39a58b refactor(c/driver): Use non-objects framework components in 
Postgres driver (#2166)
a2a39a58b is described below

commit a2a39a58be4471218720fd2cb01d0b16edf3c24a
Author: Dewey Dunnington <[email protected]>
AuthorDate: Sun Sep 22 21:24:37 2024 -0500

    refactor(c/driver): Use non-objects framework components in Postgres driver 
(#2166)
    
    This PR formalizes the names of documents the helpers in
    `framework/objects.h` and `frameworks/utility.h`. It also uses them in
    the PostgreSQL driver and removes duplicate functionality where possible
    (GetObjects in the Postgres driver is a bit of a bigger project for
    another PR).
---
 c/driver/common/utils.c                  |  66 -------
 c/driver/common/utils.h                  |   5 -
 c/driver/framework/CMakeLists.txt        |   2 +-
 c/driver/framework/catalog.cc            | 328 -------------------------------
 c/driver/framework/catalog.h             | 162 ---------------
 c/driver/framework/connection.h          |   6 +-
 c/driver/framework/meson.build           |   2 +-
 c/driver/framework/objects.cc            | 167 +++++++++++++++-
 c/driver/framework/objects.h             | 116 ++++++++++-
 c/driver/framework/statement.h           |   3 +-
 c/driver/framework/utility.cc            | 179 +++++++++++++++++
 c/driver/framework/utility.h             |  73 +++++++
 c/driver/postgresql/connection.cc        | 138 ++++---------
 c/driver/postgresql/connection.h         |   5 -
 c/driver/postgresql/statement.cc         |   3 +-
 c/driver/sqlite/sqlite.cc                |  27 ++-
 c/driver/sqlite/sqlite_test.cc           |   7 +-
 c/driver/sqlite/statement_reader.c       |   8 -
 c/driver/sqlite/statement_reader.h       |   5 -
 go/adbc/drivermgr/wrapper_sqlite_test.go |   4 -
 r/adbcpostgresql/src/Makevars.in         |   3 +-
 r/adbcpostgresql/src/Makevars.ucrt       |   3 +-
 r/adbcpostgresql/src/Makevars.win        |   3 +-
 r/adbcsqlite/src/Makevars.in             |   2 +-
 24 files changed, 597 insertions(+), 720 deletions(-)

diff --git a/c/driver/common/utils.c b/c/driver/common/utils.c
index 6daac6579..9df2b805a 100644
--- a/c/driver/common/utils.c
+++ b/c/driver/common/utils.c
@@ -235,72 +235,6 @@ struct AdbcErrorDetail CommonErrorGetDetail(const struct 
AdbcError* error, int i
   };
 }
 
-struct SingleBatchArrayStream {
-  struct ArrowSchema schema;
-  struct ArrowArray batch;
-};
-static const char* SingleBatchArrayStreamGetLastError(struct ArrowArrayStream* 
stream) {
-  (void)stream;
-  return NULL;
-}
-static int SingleBatchArrayStreamGetNext(struct ArrowArrayStream* stream,
-                                         struct ArrowArray* batch) {
-  if (!stream || !stream->private_data) return EINVAL;
-  struct SingleBatchArrayStream* impl =
-      (struct SingleBatchArrayStream*)stream->private_data;
-
-  memcpy(batch, &impl->batch, sizeof(*batch));
-  memset(&impl->batch, 0, sizeof(*batch));
-  return 0;
-}
-static int SingleBatchArrayStreamGetSchema(struct ArrowArrayStream* stream,
-                                           struct ArrowSchema* schema) {
-  if (!stream || !stream->private_data) return EINVAL;
-  struct SingleBatchArrayStream* impl =
-      (struct SingleBatchArrayStream*)stream->private_data;
-
-  return ArrowSchemaDeepCopy(&impl->schema, schema);
-}
-static void SingleBatchArrayStreamRelease(struct ArrowArrayStream* stream) {
-  if (!stream || !stream->private_data) return;
-  struct SingleBatchArrayStream* impl =
-      (struct SingleBatchArrayStream*)stream->private_data;
-  impl->schema.release(&impl->schema);
-  if (impl->batch.release) impl->batch.release(&impl->batch);
-  free(impl);
-
-  memset(stream, 0, sizeof(*stream));
-}
-
-AdbcStatusCode BatchToArrayStream(struct ArrowArray* values, struct 
ArrowSchema* schema,
-                                  struct ArrowArrayStream* stream,
-                                  struct AdbcError* error) {
-  if (!values->release) {
-    SetError(error, "ArrowArray is not initialized");
-    return ADBC_STATUS_INTERNAL;
-  } else if (!schema->release) {
-    SetError(error, "ArrowSchema is not initialized");
-    return ADBC_STATUS_INTERNAL;
-  } else if (stream->release) {
-    SetError(error, "ArrowArrayStream is already initialized");
-    return ADBC_STATUS_INTERNAL;
-  }
-
-  struct SingleBatchArrayStream* impl =
-      (struct SingleBatchArrayStream*)malloc(sizeof(*impl));
-  memcpy(&impl->schema, schema, sizeof(*schema));
-  memcpy(&impl->batch, values, sizeof(*values));
-  memset(schema, 0, sizeof(*schema));
-  memset(values, 0, sizeof(*values));
-  stream->private_data = impl;
-  stream->get_last_error = SingleBatchArrayStreamGetLastError;
-  stream->get_next = SingleBatchArrayStreamGetNext;
-  stream->get_schema = SingleBatchArrayStreamGetSchema;
-  stream->release = SingleBatchArrayStreamRelease;
-
-  return ADBC_STATUS_OK;
-}
-
 int StringBuilderInit(struct StringBuilder* builder, size_t initial_size) {
   builder->buffer = (char*)malloc(initial_size);
   if (builder->buffer == NULL) return errno;
diff --git a/c/driver/common/utils.h b/c/driver/common/utils.h
index c61ecb0e9..ec3227f88 100644
--- a/c/driver/common/utils.h
+++ b/c/driver/common/utils.h
@@ -68,11 +68,6 @@ void StringBuilderReset(struct StringBuilder* builder);
 
 #undef ADBC_CHECK_PRINTF_ATTRIBUTE
 
-/// Wrap a single batch as a stream.
-AdbcStatusCode BatchToArrayStream(struct ArrowArray* values, struct 
ArrowSchema* schema,
-                                  struct ArrowArrayStream* stream,
-                                  struct AdbcError* error);
-
 /// Check an NanoArrow status code.
 #define CHECK_NA(CODE, EXPR, ERROR)                                            
     \
   do {                                                                         
     \
diff --git a/c/driver/framework/CMakeLists.txt 
b/c/driver/framework/CMakeLists.txt
index 3efc3f1da..f5c642b53 100644
--- a/c/driver/framework/CMakeLists.txt
+++ b/c/driver/framework/CMakeLists.txt
@@ -17,7 +17,7 @@
 
 include(FetchContent)
 
-add_library(adbc_driver_framework STATIC catalog.cc objects.cc)
+add_library(adbc_driver_framework STATIC objects.cc utility.cc)
 adbc_configure_target(adbc_driver_framework)
 set_target_properties(adbc_driver_framework PROPERTIES 
POSITION_INDEPENDENT_CODE ON)
 target_include_directories(adbc_driver_framework
diff --git a/c/driver/framework/catalog.cc b/c/driver/framework/catalog.cc
deleted file mode 100644
index d5b89ea88..000000000
--- a/c/driver/framework/catalog.cc
+++ /dev/null
@@ -1,328 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements.  See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership.  The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License.  You may obtain a copy of the License at
-//
-//   http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied.  See the License for the
-// specific language governing permissions and limitations
-// under the License.
-
-#include "driver/framework/catalog.h"
-
-#include <nanoarrow/nanoarrow.hpp>
-
-namespace adbc::driver {
-
-void AdbcMakeArrayStream(struct ArrowSchema* schema, struct ArrowArray* array,
-                         struct ArrowArrayStream* out) {
-  nanoarrow::VectorArrayStream(schema, array).ToArrayStream(out);
-}
-
-Status AdbcInitConnectionGetInfoSchema(struct ArrowSchema* schema,
-                                       struct ArrowArray* array) {
-  ArrowSchemaInit(schema);
-  UNWRAP_ERRNO(Internal, ArrowSchemaSetTypeStruct(schema, /*num_columns=*/2));
-
-  UNWRAP_ERRNO(Internal, ArrowSchemaSetType(schema->children[0], 
NANOARROW_TYPE_UINT32));
-  UNWRAP_ERRNO(Internal, ArrowSchemaSetName(schema->children[0], "info_name"));
-  schema->children[0]->flags &= ~ARROW_FLAG_NULLABLE;
-
-  struct ArrowSchema* info_value = schema->children[1];
-  UNWRAP_ERRNO(Internal,
-               ArrowSchemaSetTypeUnion(info_value, NANOARROW_TYPE_DENSE_UNION, 
6));
-  UNWRAP_ERRNO(Internal, ArrowSchemaSetName(info_value, "info_value"));
-
-  UNWRAP_ERRNO(Internal,
-               ArrowSchemaSetType(info_value->children[0], 
NANOARROW_TYPE_STRING));
-  UNWRAP_ERRNO(Internal, ArrowSchemaSetName(info_value->children[0], 
"string_value"));
-  UNWRAP_ERRNO(Internal,
-               ArrowSchemaSetType(info_value->children[1], 
NANOARROW_TYPE_BOOL));
-  UNWRAP_ERRNO(Internal, ArrowSchemaSetName(info_value->children[1], 
"bool_value"));
-  UNWRAP_ERRNO(Internal,
-               ArrowSchemaSetType(info_value->children[2], 
NANOARROW_TYPE_INT64));
-  UNWRAP_ERRNO(Internal, ArrowSchemaSetName(info_value->children[2], 
"int64_value"));
-  UNWRAP_ERRNO(Internal,
-               ArrowSchemaSetType(info_value->children[3], 
NANOARROW_TYPE_INT32));
-  UNWRAP_ERRNO(Internal, ArrowSchemaSetName(info_value->children[3], 
"int32_bitmask"));
-  UNWRAP_ERRNO(Internal,
-               ArrowSchemaSetType(info_value->children[4], 
NANOARROW_TYPE_LIST));
-  UNWRAP_ERRNO(Internal, ArrowSchemaSetName(info_value->children[4], 
"string_list"));
-  UNWRAP_ERRNO(Internal, ArrowSchemaSetType(info_value->children[5], 
NANOARROW_TYPE_MAP));
-  UNWRAP_ERRNO(Internal,
-               ArrowSchemaSetName(info_value->children[5], 
"int32_to_int32_list_map"));
-
-  UNWRAP_ERRNO(Internal, 
ArrowSchemaSetType(info_value->children[4]->children[0],
-                                            NANOARROW_TYPE_STRING));
-
-  UNWRAP_ERRNO(Internal,
-               
ArrowSchemaSetType(info_value->children[5]->children[0]->children[0],
-                                  NANOARROW_TYPE_INT32));
-  info_value->children[5]->children[0]->children[0]->flags &= 
~ARROW_FLAG_NULLABLE;
-  UNWRAP_ERRNO(Internal,
-               
ArrowSchemaSetType(info_value->children[5]->children[0]->children[1],
-                                  NANOARROW_TYPE_LIST));
-  UNWRAP_ERRNO(
-      Internal,
-      
ArrowSchemaSetType(info_value->children[5]->children[0]->children[1]->children[0],
-                         NANOARROW_TYPE_INT32));
-
-  struct ArrowError na_error = {0};
-  UNWRAP_NANOARROW(na_error, Internal,
-                   ArrowArrayInitFromSchema(array, schema, &na_error));
-  UNWRAP_ERRNO(Internal, ArrowArrayStartAppending(array));
-
-  return status::Ok();
-}
-
-Status AdbcConnectionGetInfoAppendString(struct ArrowArray* array, uint32_t 
info_code,
-                                         std::string_view info_value) {
-  UNWRAP_ERRNO(Internal, ArrowArrayAppendUInt(array->children[0], info_code));
-  // Append to type variant
-  struct ArrowStringView value;
-  value.data = info_value.data();
-  value.size_bytes = static_cast<int64_t>(info_value.size());
-  UNWRAP_ERRNO(Internal, 
ArrowArrayAppendString(array->children[1]->children[0], value));
-  // Append type code/offset
-  UNWRAP_ERRNO(Internal, ArrowArrayFinishUnionElement(array->children[1], 
/*type_id=*/0));
-  return status::Ok();
-}
-
-Status AdbcConnectionGetInfoAppendInt(struct ArrowArray* array, uint32_t 
info_code,
-                                      int64_t info_value) {
-  UNWRAP_ERRNO(Internal, ArrowArrayAppendUInt(array->children[0], info_code));
-  // Append to type variant
-  UNWRAP_ERRNO(Internal,
-               ArrowArrayAppendInt(array->children[1]->children[2], 
info_value));
-  // Append type code/offset
-  UNWRAP_ERRNO(Internal, ArrowArrayFinishUnionElement(array->children[1], 
/*type_id=*/2));
-  return status::Ok();
-}
-
-Status AdbcInitConnectionObjectsSchema(struct ArrowSchema* schema) {
-  ArrowSchemaInit(schema);
-  UNWRAP_ERRNO(Internal, ArrowSchemaSetTypeStruct(schema, /*num_columns=*/2));
-  UNWRAP_ERRNO(Internal, ArrowSchemaSetType(schema->children[0], 
NANOARROW_TYPE_STRING));
-  UNWRAP_ERRNO(Internal, ArrowSchemaSetName(schema->children[0], 
"catalog_name"));
-  UNWRAP_ERRNO(Internal, ArrowSchemaSetType(schema->children[1], 
NANOARROW_TYPE_LIST));
-  UNWRAP_ERRNO(Internal, ArrowSchemaSetName(schema->children[1], 
"catalog_db_schemas"));
-  UNWRAP_ERRNO(Internal, 
ArrowSchemaSetTypeStruct(schema->children[1]->children[0], 2));
-
-  struct ArrowSchema* db_schema_schema = schema->children[1]->children[0];
-  UNWRAP_ERRNO(Internal,
-               ArrowSchemaSetType(db_schema_schema->children[0], 
NANOARROW_TYPE_STRING));
-  UNWRAP_ERRNO(Internal,
-               ArrowSchemaSetName(db_schema_schema->children[0], 
"db_schema_name"));
-  UNWRAP_ERRNO(Internal,
-               ArrowSchemaSetType(db_schema_schema->children[1], 
NANOARROW_TYPE_LIST));
-  UNWRAP_ERRNO(Internal,
-               ArrowSchemaSetName(db_schema_schema->children[1], 
"db_schema_tables"));
-  UNWRAP_ERRNO(Internal,
-               
ArrowSchemaSetTypeStruct(db_schema_schema->children[1]->children[0], 4));
-
-  struct ArrowSchema* table_schema = 
db_schema_schema->children[1]->children[0];
-  UNWRAP_ERRNO(Internal,
-               ArrowSchemaSetType(table_schema->children[0], 
NANOARROW_TYPE_STRING));
-  UNWRAP_ERRNO(Internal, ArrowSchemaSetName(table_schema->children[0], 
"table_name"));
-  table_schema->children[0]->flags &= ~ARROW_FLAG_NULLABLE;
-  UNWRAP_ERRNO(Internal,
-               ArrowSchemaSetType(table_schema->children[1], 
NANOARROW_TYPE_STRING));
-  UNWRAP_ERRNO(Internal, ArrowSchemaSetName(table_schema->children[1], 
"table_type"));
-  table_schema->children[1]->flags &= ~ARROW_FLAG_NULLABLE;
-  UNWRAP_ERRNO(Internal,
-               ArrowSchemaSetType(table_schema->children[2], 
NANOARROW_TYPE_LIST));
-  UNWRAP_ERRNO(Internal, ArrowSchemaSetName(table_schema->children[2], 
"table_columns"));
-  UNWRAP_ERRNO(Internal,
-               
ArrowSchemaSetTypeStruct(table_schema->children[2]->children[0], 19));
-  UNWRAP_ERRNO(Internal,
-               ArrowSchemaSetType(table_schema->children[3], 
NANOARROW_TYPE_LIST));
-  UNWRAP_ERRNO(Internal,
-               ArrowSchemaSetName(table_schema->children[3], 
"table_constraints"));
-  UNWRAP_ERRNO(Internal,
-               
ArrowSchemaSetTypeStruct(table_schema->children[3]->children[0], 4));
-
-  struct ArrowSchema* column_schema = table_schema->children[2]->children[0];
-  UNWRAP_ERRNO(Internal,
-               ArrowSchemaSetType(column_schema->children[0], 
NANOARROW_TYPE_STRING));
-  UNWRAP_ERRNO(Internal, ArrowSchemaSetName(column_schema->children[0], 
"column_name"));
-  column_schema->children[0]->flags &= ~ARROW_FLAG_NULLABLE;
-  UNWRAP_ERRNO(Internal,
-               ArrowSchemaSetType(column_schema->children[1], 
NANOARROW_TYPE_INT32));
-  UNWRAP_ERRNO(Internal,
-               ArrowSchemaSetName(column_schema->children[1], 
"ordinal_position"));
-  UNWRAP_ERRNO(Internal,
-               ArrowSchemaSetType(column_schema->children[2], 
NANOARROW_TYPE_STRING));
-  UNWRAP_ERRNO(Internal, ArrowSchemaSetName(column_schema->children[2], 
"remarks"));
-  UNWRAP_ERRNO(Internal,
-               ArrowSchemaSetType(column_schema->children[3], 
NANOARROW_TYPE_INT16));
-  UNWRAP_ERRNO(Internal,
-               ArrowSchemaSetName(column_schema->children[3], 
"xdbc_data_type"));
-  UNWRAP_ERRNO(Internal,
-               ArrowSchemaSetType(column_schema->children[4], 
NANOARROW_TYPE_STRING));
-  UNWRAP_ERRNO(Internal,
-               ArrowSchemaSetName(column_schema->children[4], 
"xdbc_type_name"));
-  UNWRAP_ERRNO(Internal,
-               ArrowSchemaSetType(column_schema->children[5], 
NANOARROW_TYPE_INT32));
-  UNWRAP_ERRNO(Internal,
-               ArrowSchemaSetName(column_schema->children[5], 
"xdbc_column_size"));
-  UNWRAP_ERRNO(Internal,
-               ArrowSchemaSetType(column_schema->children[6], 
NANOARROW_TYPE_INT16));
-  UNWRAP_ERRNO(Internal,
-               ArrowSchemaSetName(column_schema->children[6], 
"xdbc_decimal_digits"));
-  UNWRAP_ERRNO(Internal,
-               ArrowSchemaSetType(column_schema->children[7], 
NANOARROW_TYPE_INT16));
-  UNWRAP_ERRNO(Internal,
-               ArrowSchemaSetName(column_schema->children[7], 
"xdbc_num_prec_radix"));
-  UNWRAP_ERRNO(Internal,
-               ArrowSchemaSetType(column_schema->children[8], 
NANOARROW_TYPE_INT16));
-  UNWRAP_ERRNO(Internal, ArrowSchemaSetName(column_schema->children[8], 
"xdbc_nullable"));
-  UNWRAP_ERRNO(Internal,
-               ArrowSchemaSetType(column_schema->children[9], 
NANOARROW_TYPE_STRING));
-  UNWRAP_ERRNO(Internal,
-               ArrowSchemaSetName(column_schema->children[9], 
"xdbc_column_def"));
-  UNWRAP_ERRNO(Internal,
-               ArrowSchemaSetType(column_schema->children[10], 
NANOARROW_TYPE_INT16));
-  UNWRAP_ERRNO(Internal,
-               ArrowSchemaSetName(column_schema->children[10], 
"xdbc_sql_data_type"));
-  UNWRAP_ERRNO(Internal,
-               ArrowSchemaSetType(column_schema->children[11], 
NANOARROW_TYPE_INT16));
-  UNWRAP_ERRNO(Internal,
-               ArrowSchemaSetName(column_schema->children[11], 
"xdbc_datetime_sub"));
-  UNWRAP_ERRNO(Internal,
-               ArrowSchemaSetType(column_schema->children[12], 
NANOARROW_TYPE_INT32));
-  UNWRAP_ERRNO(Internal,
-               ArrowSchemaSetName(column_schema->children[12], 
"xdbc_char_octet_length"));
-  UNWRAP_ERRNO(Internal,
-               ArrowSchemaSetType(column_schema->children[13], 
NANOARROW_TYPE_STRING));
-  UNWRAP_ERRNO(Internal,
-               ArrowSchemaSetName(column_schema->children[13], 
"xdbc_is_nullable"));
-  UNWRAP_ERRNO(Internal,
-               ArrowSchemaSetType(column_schema->children[14], 
NANOARROW_TYPE_STRING));
-  UNWRAP_ERRNO(Internal,
-               ArrowSchemaSetName(column_schema->children[14], 
"xdbc_scope_catalog"));
-  UNWRAP_ERRNO(Internal,
-               ArrowSchemaSetType(column_schema->children[15], 
NANOARROW_TYPE_STRING));
-  UNWRAP_ERRNO(Internal,
-               ArrowSchemaSetName(column_schema->children[15], 
"xdbc_scope_schema"));
-  UNWRAP_ERRNO(Internal,
-               ArrowSchemaSetType(column_schema->children[16], 
NANOARROW_TYPE_STRING));
-  UNWRAP_ERRNO(Internal,
-               ArrowSchemaSetName(column_schema->children[16], 
"xdbc_scope_table"));
-  UNWRAP_ERRNO(Internal,
-               ArrowSchemaSetType(column_schema->children[17], 
NANOARROW_TYPE_BOOL));
-  UNWRAP_ERRNO(Internal,
-               ArrowSchemaSetName(column_schema->children[17], 
"xdbc_is_autoincrement"));
-  UNWRAP_ERRNO(Internal,
-               ArrowSchemaSetType(column_schema->children[18], 
NANOARROW_TYPE_BOOL));
-  UNWRAP_ERRNO(Internal, ArrowSchemaSetName(column_schema->children[18],
-                                            "xdbc_is_generatedcolumn"));
-
-  struct ArrowSchema* constraint_schema = 
table_schema->children[3]->children[0];
-  UNWRAP_ERRNO(Internal,
-               ArrowSchemaSetType(constraint_schema->children[0], 
NANOARROW_TYPE_STRING));
-  UNWRAP_ERRNO(Internal,
-               ArrowSchemaSetName(constraint_schema->children[0], 
"constraint_name"));
-  UNWRAP_ERRNO(Internal,
-               ArrowSchemaSetType(constraint_schema->children[1], 
NANOARROW_TYPE_STRING));
-  UNWRAP_ERRNO(Internal,
-               ArrowSchemaSetName(constraint_schema->children[1], 
"constraint_type"));
-  constraint_schema->children[1]->flags &= ~ARROW_FLAG_NULLABLE;
-  UNWRAP_ERRNO(Internal,
-               ArrowSchemaSetType(constraint_schema->children[2], 
NANOARROW_TYPE_LIST));
-  UNWRAP_ERRNO(Internal, ArrowSchemaSetName(constraint_schema->children[2],
-                                            "constraint_column_names"));
-  UNWRAP_ERRNO(Internal, 
ArrowSchemaSetType(constraint_schema->children[2]->children[0],
-                                            NANOARROW_TYPE_STRING));
-  constraint_schema->children[2]->flags &= ~ARROW_FLAG_NULLABLE;
-  UNWRAP_ERRNO(Internal,
-               ArrowSchemaSetType(constraint_schema->children[3], 
NANOARROW_TYPE_LIST));
-  UNWRAP_ERRNO(Internal, ArrowSchemaSetName(constraint_schema->children[3],
-                                            "constraint_column_usage"));
-  UNWRAP_ERRNO(Internal,
-               
ArrowSchemaSetTypeStruct(constraint_schema->children[3]->children[0], 4));
-
-  struct ArrowSchema* usage_schema = 
constraint_schema->children[3]->children[0];
-  UNWRAP_ERRNO(Internal,
-               ArrowSchemaSetType(usage_schema->children[0], 
NANOARROW_TYPE_STRING));
-  UNWRAP_ERRNO(Internal, ArrowSchemaSetName(usage_schema->children[0], 
"fk_catalog"));
-  UNWRAP_ERRNO(Internal,
-               ArrowSchemaSetType(usage_schema->children[1], 
NANOARROW_TYPE_STRING));
-  UNWRAP_ERRNO(Internal, ArrowSchemaSetName(usage_schema->children[1], 
"fk_db_schema"));
-  UNWRAP_ERRNO(Internal,
-               ArrowSchemaSetType(usage_schema->children[2], 
NANOARROW_TYPE_STRING));
-  UNWRAP_ERRNO(Internal, ArrowSchemaSetName(usage_schema->children[2], 
"fk_table"));
-  usage_schema->children[2]->flags &= ~ARROW_FLAG_NULLABLE;
-  UNWRAP_ERRNO(Internal,
-               ArrowSchemaSetType(usage_schema->children[3], 
NANOARROW_TYPE_STRING));
-  UNWRAP_ERRNO(Internal, ArrowSchemaSetName(usage_schema->children[3], 
"fk_column_name"));
-  usage_schema->children[3]->flags &= ~ARROW_FLAG_NULLABLE;
-
-  return status::Ok();
-}
-
-Status AdbcGetInfo(std::vector<InfoValue> infos, struct ArrowArrayStream* out) 
{
-  nanoarrow::UniqueSchema schema;
-  nanoarrow::UniqueArray array;
-
-  UNWRAP_STATUS(AdbcInitConnectionGetInfoSchema(schema.get(), array.get()));
-
-  for (const auto& info : infos) {
-    UNWRAP_STATUS(std::visit(
-        [&](auto&& value) -> Status {
-          using T = std::decay_t<decltype(value)>;
-          if constexpr (std::is_same_v<T, std::string>) {
-            return AdbcConnectionGetInfoAppendString(array.get(), info.code, 
value);
-          } else if constexpr (std::is_same_v<T, int64_t>) {
-            return AdbcConnectionGetInfoAppendInt(array.get(), info.code, 
value);
-          } else {
-            static_assert(!sizeof(T), "info value type not implemented");
-          }
-          return status::Ok();
-        },
-        info.value));
-    UNWRAP_ERRNO(Internal, ArrowArrayFinishElement(array.get()));
-  }
-
-  struct ArrowError na_error = {0};
-  UNWRAP_NANOARROW(na_error, Internal,
-                   ArrowArrayFinishBuildingDefault(array.get(), &na_error));
-  nanoarrow::VectorArrayStream(schema.get(), array.get()).ToArrayStream(out);
-  return status::Ok();
-}
-
-Status AdbcGetTableTypes(const std::vector<std::string>& table_types,
-                         struct ArrowArrayStream* out) {
-  nanoarrow::UniqueArray array;
-  nanoarrow::UniqueSchema schema;
-  ArrowSchemaInit(schema.get());
-
-  UNWRAP_ERRNO(Internal, ArrowSchemaSetType(schema.get(), 
NANOARROW_TYPE_STRUCT));
-  UNWRAP_ERRNO(Internal, ArrowSchemaAllocateChildren(schema.get(), 
/*num_columns=*/1));
-  ArrowSchemaInit(schema.get()->children[0]);
-  UNWRAP_ERRNO(Internal,
-               ArrowSchemaSetType(schema.get()->children[0], 
NANOARROW_TYPE_STRING));
-  UNWRAP_ERRNO(Internal, ArrowSchemaSetName(schema.get()->children[0], 
"table_type"));
-  schema.get()->children[0]->flags &= ~ARROW_FLAG_NULLABLE;
-
-  UNWRAP_ERRNO(Internal, ArrowArrayInitFromSchema(array.get(), schema.get(), 
NULL));
-  UNWRAP_ERRNO(Internal, ArrowArrayStartAppending(array.get()));
-
-  for (std::string const& table_type : table_types) {
-    UNWRAP_ERRNO(Internal, ArrowArrayAppendString(array->children[0],
-                                                  
ArrowCharView(table_type.c_str())));
-    UNWRAP_ERRNO(Internal, ArrowArrayFinishElement(array.get()));
-  }
-
-  UNWRAP_ERRNO(Internal, ArrowArrayFinishBuildingDefault(array.get(), 
nullptr));
-  nanoarrow::VectorArrayStream(schema.get(), array.get()).ToArrayStream(out);
-  return status::Ok();
-}
-
-}  // namespace adbc::driver
diff --git a/c/driver/framework/catalog.h b/c/driver/framework/catalog.h
deleted file mode 100644
index 8c0eff17e..000000000
--- a/c/driver/framework/catalog.h
+++ /dev/null
@@ -1,162 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements.  See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership.  The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License.  You may obtain a copy of the License at
-//
-//   http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied.  See the License for the
-// specific language governing permissions and limitations
-// under the License.
-
-#pragma once
-
-#include <cstdint>
-#include <optional>
-#include <string>
-#include <string_view>
-#include <utility>
-#include <variant>
-#include <vector>
-
-#include <arrow-adbc/adbc.h>
-
-#include "driver/framework/status.h"
-
-namespace adbc::driver {
-
-/// \defgroup adbc-framework-catalog Catalog Utilities
-/// Utilities for implementing catalog/metadata-related functions.
-///
-/// @{
-
-/// \brief The GetObjects level.
-enum class GetObjectsDepth {
-  kCatalogs,
-  kSchemas,
-  kTables,
-  kColumns,
-};
-
-/// \brief Helper to implement GetObjects.
-struct GetObjectsHelper {
-  virtual ~GetObjectsHelper() = default;
-
-  struct Table {
-    std::string_view name;
-    std::string_view type;
-  };
-
-  struct ColumnXdbc {
-    std::optional<int16_t> xdbc_data_type;
-    std::optional<std::string_view> xdbc_type_name;
-    std::optional<int32_t> xdbc_column_size;
-    std::optional<int16_t> xdbc_decimal_digits;
-    std::optional<int16_t> xdbc_num_prec_radix;
-    std::optional<int16_t> xdbc_nullable;
-    std::optional<std::string_view> xdbc_column_def;
-    std::optional<int16_t> xdbc_sql_data_type;
-    std::optional<int16_t> xdbc_datetime_sub;
-    std::optional<int32_t> xdbc_char_octet_length;
-    std::optional<std::string_view> xdbc_is_nullable;
-    std::optional<std::string_view> xdbc_scope_catalog;
-    std::optional<std::string_view> xdbc_scope_schema;
-    std::optional<std::string_view> xdbc_scope_table;
-    std::optional<bool> xdbc_is_autoincrement;
-    std::optional<bool> xdbc_is_generatedcolumn;
-  };
-
-  struct Column {
-    std::string_view column_name;
-    int32_t ordinal_position;
-    std::optional<std::string_view> remarks;
-    std::optional<ColumnXdbc> xdbc;
-  };
-
-  struct ConstraintUsage {
-    std::optional<std::string_view> catalog;
-    std::optional<std::string_view> schema;
-    std::string_view table;
-    std::string_view column;
-  };
-
-  struct Constraint {
-    std::optional<std::string_view> name;
-    std::string_view type;
-    std::vector<std::string_view> column_names;
-    std::optional<std::vector<ConstraintUsage>> usage;
-  };
-
-  Status Close() { return status::Ok(); }
-
-  /// \brief Fetch all metadata needed.  The driver is free to delay loading
-  /// but this gives it a chance to load data up front.
-  virtual Status Load(GetObjectsDepth depth,
-                      std::optional<std::string_view> catalog_filter,
-                      std::optional<std::string_view> schema_filter,
-                      std::optional<std::string_view> table_filter,
-                      std::optional<std::string_view> column_filter,
-                      const std::vector<std::string_view>& table_types) {
-    return status::NotImplemented("GetObjects");
-  }
-
-  virtual Status LoadCatalogs() {
-    return status::NotImplemented("GetObjects at depth = catalog");
-  };
-
-  virtual Result<std::optional<std::string_view>> NextCatalog() { return 
std::nullopt; }
-
-  virtual Status LoadSchemas(std::string_view catalog) {
-    return status::NotImplemented("GetObjects at depth = schema");
-  };
-
-  virtual Result<std::optional<std::string_view>> NextSchema() { return 
std::nullopt; }
-
-  virtual Status LoadTables(std::string_view catalog, std::string_view schema) 
{
-    return status::NotImplemented("GetObjects at depth = table");
-  };
-
-  virtual Result<std::optional<Table>> NextTable() { return std::nullopt; }
-
-  virtual Status LoadColumns(std::string_view catalog, std::string_view schema,
-                             std::string_view table) {
-    return status::NotImplemented("GetObjects at depth = column");
-  };
-
-  virtual Result<std::optional<Column>> NextColumn() { return std::nullopt; }
-
-  virtual Result<std::optional<Constraint>> NextConstraint() { return 
std::nullopt; }
-};
-
-struct InfoValue {
-  uint32_t code;
-  std::variant<std::string, int64_t> value;
-
-  explicit InfoValue(uint32_t code, std::variant<std::string, int64_t> value)
-      : code(code), value(std::move(value)) {}
-};
-
-void AdbcMakeArrayStream(struct ArrowSchema* schema, struct ArrowArray* array,
-                         struct ArrowArrayStream* out);
-
-Status AdbcGetInfo(std::vector<InfoValue> infos, struct ArrowArrayStream* out);
-
-Status AdbcGetTableTypes(const std::vector<std::string>& table_types,
-                         struct ArrowArrayStream* out);
-
-Status AdbcInitConnectionGetInfoSchema(struct ArrowSchema* schema,
-                                       struct ArrowArray* array);
-Status AdbcConnectionGetInfoAppendString(struct ArrowArray* array, uint32_t 
info_code,
-                                         std::string_view info_value);
-Status AdbcConnectionGetInfoAppendInt(struct ArrowArray* array, uint32_t 
info_code,
-                                      int64_t info_value);
-Status AdbcInitConnectionObjectsSchema(struct ArrowSchema* schema);
-/// @}
-
-}  // namespace adbc::driver
diff --git a/c/driver/framework/connection.h b/c/driver/framework/connection.h
index f9e329ec1..da3aae107 100644
--- a/c/driver/framework/connection.h
+++ b/c/driver/framework/connection.h
@@ -27,8 +27,8 @@
 #include <arrow-adbc/adbc.h>
 
 #include "driver/framework/base_driver.h"
-#include "driver/framework/catalog.h"
 #include "driver/framework/objects.h"
+#include "driver/framework/utility.h"
 
 namespace adbc::driver {
 /// \brief The CRTP base implementation of an AdbcConnection.
@@ -86,7 +86,7 @@ class Connection : public ObjectBase {
 
     std::vector<uint32_t> codes(info_codes, info_codes + info_codes_length);
     RAISE_RESULT(error, auto infos, impl().InfoImpl(codes));
-    RAISE_STATUS(error, AdbcGetInfo(infos, out));
+    RAISE_STATUS(error, MakeGetInfoStream(infos, out));
     return ADBC_STATUS_OK;
   }
 
@@ -204,7 +204,7 @@ class Connection : public ObjectBase {
     }
 
     RAISE_RESULT(error, std::vector<std::string> table_types, 
impl().GetTableTypesImpl());
-    RAISE_STATUS(error, AdbcGetTableTypes(table_types, out));
+    RAISE_STATUS(error, MakeTableTypesStream(table_types, out));
     return ADBC_STATUS_OK;
   }
 
diff --git a/c/driver/framework/meson.build b/c/driver/framework/meson.build
index 432cc5bb7..08be53eac 100644
--- a/c/driver/framework/meson.build
+++ b/c/driver/framework/meson.build
@@ -18,8 +18,8 @@
 adbc_framework_lib = library(
     'adbc_driver_framework',
     sources: [
-        'catalog.cc',
         'objects.cc',
+        'utility.cc',
     ],
     include_directories: [include_dir, c_dir],
     link_with: [adbc_common_lib],
diff --git a/c/driver/framework/objects.cc b/c/driver/framework/objects.cc
index 1d5e9105f..eaf62351d 100644
--- a/c/driver/framework/objects.cc
+++ b/c/driver/framework/objects.cc
@@ -21,11 +21,172 @@
 
 #include "nanoarrow/nanoarrow.hpp"
 
-#include "driver/framework/catalog.h"
 #include "driver/framework/status.h"
+#include "driver/framework/utility.h"
 
 namespace adbc::driver {
 
+Status MakeGetObjectsSchema(struct ArrowSchema* schema) {
+  ArrowSchemaInit(schema);
+  UNWRAP_ERRNO(Internal, ArrowSchemaSetTypeStruct(schema, /*num_columns=*/2));
+  UNWRAP_ERRNO(Internal, ArrowSchemaSetType(schema->children[0], 
NANOARROW_TYPE_STRING));
+  UNWRAP_ERRNO(Internal, ArrowSchemaSetName(schema->children[0], 
"catalog_name"));
+  UNWRAP_ERRNO(Internal, ArrowSchemaSetType(schema->children[1], 
NANOARROW_TYPE_LIST));
+  UNWRAP_ERRNO(Internal, ArrowSchemaSetName(schema->children[1], 
"catalog_db_schemas"));
+  UNWRAP_ERRNO(Internal, 
ArrowSchemaSetTypeStruct(schema->children[1]->children[0], 2));
+
+  struct ArrowSchema* db_schema_schema = schema->children[1]->children[0];
+  UNWRAP_ERRNO(Internal,
+               ArrowSchemaSetType(db_schema_schema->children[0], 
NANOARROW_TYPE_STRING));
+  UNWRAP_ERRNO(Internal,
+               ArrowSchemaSetName(db_schema_schema->children[0], 
"db_schema_name"));
+  UNWRAP_ERRNO(Internal,
+               ArrowSchemaSetType(db_schema_schema->children[1], 
NANOARROW_TYPE_LIST));
+  UNWRAP_ERRNO(Internal,
+               ArrowSchemaSetName(db_schema_schema->children[1], 
"db_schema_tables"));
+  UNWRAP_ERRNO(Internal,
+               
ArrowSchemaSetTypeStruct(db_schema_schema->children[1]->children[0], 4));
+
+  struct ArrowSchema* table_schema = 
db_schema_schema->children[1]->children[0];
+  UNWRAP_ERRNO(Internal,
+               ArrowSchemaSetType(table_schema->children[0], 
NANOARROW_TYPE_STRING));
+  UNWRAP_ERRNO(Internal, ArrowSchemaSetName(table_schema->children[0], 
"table_name"));
+  table_schema->children[0]->flags &= ~ARROW_FLAG_NULLABLE;
+  UNWRAP_ERRNO(Internal,
+               ArrowSchemaSetType(table_schema->children[1], 
NANOARROW_TYPE_STRING));
+  UNWRAP_ERRNO(Internal, ArrowSchemaSetName(table_schema->children[1], 
"table_type"));
+  table_schema->children[1]->flags &= ~ARROW_FLAG_NULLABLE;
+  UNWRAP_ERRNO(Internal,
+               ArrowSchemaSetType(table_schema->children[2], 
NANOARROW_TYPE_LIST));
+  UNWRAP_ERRNO(Internal, ArrowSchemaSetName(table_schema->children[2], 
"table_columns"));
+  UNWRAP_ERRNO(Internal,
+               
ArrowSchemaSetTypeStruct(table_schema->children[2]->children[0], 19));
+  UNWRAP_ERRNO(Internal,
+               ArrowSchemaSetType(table_schema->children[3], 
NANOARROW_TYPE_LIST));
+  UNWRAP_ERRNO(Internal,
+               ArrowSchemaSetName(table_schema->children[3], 
"table_constraints"));
+  UNWRAP_ERRNO(Internal,
+               
ArrowSchemaSetTypeStruct(table_schema->children[3]->children[0], 4));
+
+  struct ArrowSchema* column_schema = table_schema->children[2]->children[0];
+  UNWRAP_ERRNO(Internal,
+               ArrowSchemaSetType(column_schema->children[0], 
NANOARROW_TYPE_STRING));
+  UNWRAP_ERRNO(Internal, ArrowSchemaSetName(column_schema->children[0], 
"column_name"));
+  column_schema->children[0]->flags &= ~ARROW_FLAG_NULLABLE;
+  UNWRAP_ERRNO(Internal,
+               ArrowSchemaSetType(column_schema->children[1], 
NANOARROW_TYPE_INT32));
+  UNWRAP_ERRNO(Internal,
+               ArrowSchemaSetName(column_schema->children[1], 
"ordinal_position"));
+  UNWRAP_ERRNO(Internal,
+               ArrowSchemaSetType(column_schema->children[2], 
NANOARROW_TYPE_STRING));
+  UNWRAP_ERRNO(Internal, ArrowSchemaSetName(column_schema->children[2], 
"remarks"));
+  UNWRAP_ERRNO(Internal,
+               ArrowSchemaSetType(column_schema->children[3], 
NANOARROW_TYPE_INT16));
+  UNWRAP_ERRNO(Internal,
+               ArrowSchemaSetName(column_schema->children[3], 
"xdbc_data_type"));
+  UNWRAP_ERRNO(Internal,
+               ArrowSchemaSetType(column_schema->children[4], 
NANOARROW_TYPE_STRING));
+  UNWRAP_ERRNO(Internal,
+               ArrowSchemaSetName(column_schema->children[4], 
"xdbc_type_name"));
+  UNWRAP_ERRNO(Internal,
+               ArrowSchemaSetType(column_schema->children[5], 
NANOARROW_TYPE_INT32));
+  UNWRAP_ERRNO(Internal,
+               ArrowSchemaSetName(column_schema->children[5], 
"xdbc_column_size"));
+  UNWRAP_ERRNO(Internal,
+               ArrowSchemaSetType(column_schema->children[6], 
NANOARROW_TYPE_INT16));
+  UNWRAP_ERRNO(Internal,
+               ArrowSchemaSetName(column_schema->children[6], 
"xdbc_decimal_digits"));
+  UNWRAP_ERRNO(Internal,
+               ArrowSchemaSetType(column_schema->children[7], 
NANOARROW_TYPE_INT16));
+  UNWRAP_ERRNO(Internal,
+               ArrowSchemaSetName(column_schema->children[7], 
"xdbc_num_prec_radix"));
+  UNWRAP_ERRNO(Internal,
+               ArrowSchemaSetType(column_schema->children[8], 
NANOARROW_TYPE_INT16));
+  UNWRAP_ERRNO(Internal, ArrowSchemaSetName(column_schema->children[8], 
"xdbc_nullable"));
+  UNWRAP_ERRNO(Internal,
+               ArrowSchemaSetType(column_schema->children[9], 
NANOARROW_TYPE_STRING));
+  UNWRAP_ERRNO(Internal,
+               ArrowSchemaSetName(column_schema->children[9], 
"xdbc_column_def"));
+  UNWRAP_ERRNO(Internal,
+               ArrowSchemaSetType(column_schema->children[10], 
NANOARROW_TYPE_INT16));
+  UNWRAP_ERRNO(Internal,
+               ArrowSchemaSetName(column_schema->children[10], 
"xdbc_sql_data_type"));
+  UNWRAP_ERRNO(Internal,
+               ArrowSchemaSetType(column_schema->children[11], 
NANOARROW_TYPE_INT16));
+  UNWRAP_ERRNO(Internal,
+               ArrowSchemaSetName(column_schema->children[11], 
"xdbc_datetime_sub"));
+  UNWRAP_ERRNO(Internal,
+               ArrowSchemaSetType(column_schema->children[12], 
NANOARROW_TYPE_INT32));
+  UNWRAP_ERRNO(Internal,
+               ArrowSchemaSetName(column_schema->children[12], 
"xdbc_char_octet_length"));
+  UNWRAP_ERRNO(Internal,
+               ArrowSchemaSetType(column_schema->children[13], 
NANOARROW_TYPE_STRING));
+  UNWRAP_ERRNO(Internal,
+               ArrowSchemaSetName(column_schema->children[13], 
"xdbc_is_nullable"));
+  UNWRAP_ERRNO(Internal,
+               ArrowSchemaSetType(column_schema->children[14], 
NANOARROW_TYPE_STRING));
+  UNWRAP_ERRNO(Internal,
+               ArrowSchemaSetName(column_schema->children[14], 
"xdbc_scope_catalog"));
+  UNWRAP_ERRNO(Internal,
+               ArrowSchemaSetType(column_schema->children[15], 
NANOARROW_TYPE_STRING));
+  UNWRAP_ERRNO(Internal,
+               ArrowSchemaSetName(column_schema->children[15], 
"xdbc_scope_schema"));
+  UNWRAP_ERRNO(Internal,
+               ArrowSchemaSetType(column_schema->children[16], 
NANOARROW_TYPE_STRING));
+  UNWRAP_ERRNO(Internal,
+               ArrowSchemaSetName(column_schema->children[16], 
"xdbc_scope_table"));
+  UNWRAP_ERRNO(Internal,
+               ArrowSchemaSetType(column_schema->children[17], 
NANOARROW_TYPE_BOOL));
+  UNWRAP_ERRNO(Internal,
+               ArrowSchemaSetName(column_schema->children[17], 
"xdbc_is_autoincrement"));
+  UNWRAP_ERRNO(Internal,
+               ArrowSchemaSetType(column_schema->children[18], 
NANOARROW_TYPE_BOOL));
+  UNWRAP_ERRNO(Internal, ArrowSchemaSetName(column_schema->children[18],
+                                            "xdbc_is_generatedcolumn"));
+
+  struct ArrowSchema* constraint_schema = 
table_schema->children[3]->children[0];
+  UNWRAP_ERRNO(Internal,
+               ArrowSchemaSetType(constraint_schema->children[0], 
NANOARROW_TYPE_STRING));
+  UNWRAP_ERRNO(Internal,
+               ArrowSchemaSetName(constraint_schema->children[0], 
"constraint_name"));
+  UNWRAP_ERRNO(Internal,
+               ArrowSchemaSetType(constraint_schema->children[1], 
NANOARROW_TYPE_STRING));
+  UNWRAP_ERRNO(Internal,
+               ArrowSchemaSetName(constraint_schema->children[1], 
"constraint_type"));
+  constraint_schema->children[1]->flags &= ~ARROW_FLAG_NULLABLE;
+  UNWRAP_ERRNO(Internal,
+               ArrowSchemaSetType(constraint_schema->children[2], 
NANOARROW_TYPE_LIST));
+  UNWRAP_ERRNO(Internal, ArrowSchemaSetName(constraint_schema->children[2],
+                                            "constraint_column_names"));
+  UNWRAP_ERRNO(Internal, 
ArrowSchemaSetType(constraint_schema->children[2]->children[0],
+                                            NANOARROW_TYPE_STRING));
+  constraint_schema->children[2]->flags &= ~ARROW_FLAG_NULLABLE;
+  UNWRAP_ERRNO(Internal,
+               ArrowSchemaSetType(constraint_schema->children[3], 
NANOARROW_TYPE_LIST));
+  UNWRAP_ERRNO(Internal, ArrowSchemaSetName(constraint_schema->children[3],
+                                            "constraint_column_usage"));
+  UNWRAP_ERRNO(Internal,
+               
ArrowSchemaSetTypeStruct(constraint_schema->children[3]->children[0], 4));
+
+  struct ArrowSchema* usage_schema = 
constraint_schema->children[3]->children[0];
+  UNWRAP_ERRNO(Internal,
+               ArrowSchemaSetType(usage_schema->children[0], 
NANOARROW_TYPE_STRING));
+  UNWRAP_ERRNO(Internal, ArrowSchemaSetName(usage_schema->children[0], 
"fk_catalog"));
+  UNWRAP_ERRNO(Internal,
+               ArrowSchemaSetType(usage_schema->children[1], 
NANOARROW_TYPE_STRING));
+  UNWRAP_ERRNO(Internal, ArrowSchemaSetName(usage_schema->children[1], 
"fk_db_schema"));
+  UNWRAP_ERRNO(Internal,
+               ArrowSchemaSetType(usage_schema->children[2], 
NANOARROW_TYPE_STRING));
+  UNWRAP_ERRNO(Internal, ArrowSchemaSetName(usage_schema->children[2], 
"fk_table"));
+  usage_schema->children[2]->flags &= ~ARROW_FLAG_NULLABLE;
+  UNWRAP_ERRNO(Internal,
+               ArrowSchemaSetType(usage_schema->children[3], 
NANOARROW_TYPE_STRING));
+  UNWRAP_ERRNO(Internal, ArrowSchemaSetName(usage_schema->children[3], 
"fk_column_name"));
+  usage_schema->children[3]->flags &= ~ARROW_FLAG_NULLABLE;
+
+  return status::Ok();
+}
+
 namespace {
 /// \brief A helper to convert std::string_view to Nanoarrow's ArrowStringView.
 ArrowStringView ToStringView(std::string_view s) {
@@ -115,7 +276,7 @@ struct GetObjectsBuilder {
 
  private:
   Status InitArrowArray() {
-    UNWRAP_STATUS(AdbcInitConnectionObjectsSchema(schema));
+    UNWRAP_STATUS(MakeGetObjectsSchema(schema));
     UNWRAP_NANOARROW(na_error, Internal,
                      ArrowArrayInitFromSchema(array, schema, &na_error));
     UNWRAP_ERRNO(Internal, ArrowArrayStartAppending(array));
@@ -365,7 +526,7 @@ Status BuildGetObjects(GetObjectsHelper* helper, 
GetObjectsDepth depth,
                                   table_filter, column_filter, table_types, 
schema.get(),
                                   array.get())
                     .Build());
-  nanoarrow::VectorArrayStream(schema.get(), array.get()).ToArrayStream(out);
+  MakeArrayStream(schema.get(), array.get(), out);
   return status::Ok();
 }
 }  // namespace adbc::driver
diff --git a/c/driver/framework/objects.h b/c/driver/framework/objects.h
index ffd2004e0..a855265ca 100644
--- a/c/driver/framework/objects.h
+++ b/c/driver/framework/objects.h
@@ -21,13 +21,121 @@
 #include <string_view>
 #include <vector>
 
-#include <nanoarrow/nanoarrow.h>
-
-#include "driver/framework/catalog.h"
+#include <arrow-adbc/adbc.h>
 #include "driver/framework/status.h"
 #include "driver/framework/type_fwd.h"
 
 namespace adbc::driver {
+
+/// \defgroup adbc-framework-catalog Catalog Utilities
+/// Utilities for implementing catalog/metadata-related functions.
+///
+/// @{
+
+/// \brief Create the ArrowSchema for AdbcConnectionGetObjects().
+Status MakeGetObjectsSchema(ArrowSchema* schema);
+
+/// \brief The GetObjects level.
+enum class GetObjectsDepth {
+  kCatalogs,
+  kSchemas,
+  kTables,
+  kColumns,
+};
+
+/// \brief Helper to implement GetObjects.
+///
+/// Drivers can implement methods of the GetObjectsHelper in a driver-specific
+/// class to get a compliant implementation of AdbcConnectionGetObjects().
+struct GetObjectsHelper {
+  virtual ~GetObjectsHelper() = default;
+
+  struct Table {
+    std::string_view name;
+    std::string_view type;
+  };
+
+  struct ColumnXdbc {
+    std::optional<int16_t> xdbc_data_type;
+    std::optional<std::string_view> xdbc_type_name;
+    std::optional<int32_t> xdbc_column_size;
+    std::optional<int16_t> xdbc_decimal_digits;
+    std::optional<int16_t> xdbc_num_prec_radix;
+    std::optional<int16_t> xdbc_nullable;
+    std::optional<std::string_view> xdbc_column_def;
+    std::optional<int16_t> xdbc_sql_data_type;
+    std::optional<int16_t> xdbc_datetime_sub;
+    std::optional<int32_t> xdbc_char_octet_length;
+    std::optional<std::string_view> xdbc_is_nullable;
+    std::optional<std::string_view> xdbc_scope_catalog;
+    std::optional<std::string_view> xdbc_scope_schema;
+    std::optional<std::string_view> xdbc_scope_table;
+    std::optional<bool> xdbc_is_autoincrement;
+    std::optional<bool> xdbc_is_generatedcolumn;
+  };
+
+  struct Column {
+    std::string_view column_name;
+    int32_t ordinal_position;
+    std::optional<std::string_view> remarks;
+    std::optional<ColumnXdbc> xdbc;
+  };
+
+  struct ConstraintUsage {
+    std::optional<std::string_view> catalog;
+    std::optional<std::string_view> schema;
+    std::string_view table;
+    std::string_view column;
+  };
+
+  struct Constraint {
+    std::optional<std::string_view> name;
+    std::string_view type;
+    std::vector<std::string_view> column_names;
+    std::optional<std::vector<ConstraintUsage>> usage;
+  };
+
+  Status Close() { return status::Ok(); }
+
+  /// \brief Fetch all metadata needed.  The driver is free to delay loading
+  /// but this gives it a chance to load data up front.
+  virtual Status Load(GetObjectsDepth depth,
+                      std::optional<std::string_view> catalog_filter,
+                      std::optional<std::string_view> schema_filter,
+                      std::optional<std::string_view> table_filter,
+                      std::optional<std::string_view> column_filter,
+                      const std::vector<std::string_view>& table_types) {
+    return status::NotImplemented("GetObjects");
+  }
+
+  virtual Status LoadCatalogs() {
+    return status::NotImplemented("GetObjects at depth = catalog");
+  };
+
+  virtual Result<std::optional<std::string_view>> NextCatalog() { return 
std::nullopt; }
+
+  virtual Status LoadSchemas(std::string_view catalog) {
+    return status::NotImplemented("GetObjects at depth = schema");
+  };
+
+  virtual Result<std::optional<std::string_view>> NextSchema() { return 
std::nullopt; }
+
+  virtual Status LoadTables(std::string_view catalog, std::string_view schema) 
{
+    return status::NotImplemented("GetObjects at depth = table");
+  };
+
+  virtual Result<std::optional<Table>> NextTable() { return std::nullopt; }
+
+  virtual Status LoadColumns(std::string_view catalog, std::string_view schema,
+                             std::string_view table) {
+    return status::NotImplemented("GetObjects at depth = column");
+  };
+
+  virtual Result<std::optional<Column>> NextColumn() { return std::nullopt; }
+
+  virtual Result<std::optional<Constraint>> NextConstraint() { return 
std::nullopt; }
+};
+
 /// \brief A helper that implements GetObjects.
 /// The out/helper lifetime are caller-managed.
 Status BuildGetObjects(GetObjectsHelper* helper, GetObjectsDepth depth,
@@ -36,5 +144,5 @@ Status BuildGetObjects(GetObjectsHelper* helper, 
GetObjectsDepth depth,
                        std::optional<std::string_view> table_filter,
                        std::optional<std::string_view> column_filter,
                        const std::vector<std::string_view>& table_types,
-                       struct ArrowArrayStream* out);
+                       ArrowArrayStream* out);
 }  // namespace adbc::driver
diff --git a/c/driver/framework/statement.h b/c/driver/framework/statement.h
index af9eee03f..c07324849 100644
--- a/c/driver/framework/statement.h
+++ b/c/driver/framework/statement.h
@@ -27,6 +27,7 @@
 
 #include "driver/framework/base_driver.h"
 #include "driver/framework/status.h"
+#include "driver/framework/utility.h"
 
 namespace adbc::driver {
 
@@ -87,7 +88,7 @@ class Statement : public BaseStatement<Derived> {
           .ToAdbc(error);
     }
     if (bind_parameters_.release) bind_parameters_.release(&bind_parameters_);
-    AdbcMakeArrayStream(schema, values, &bind_parameters_);
+    MakeArrayStream(schema, values, &bind_parameters_);
     return ADBC_STATUS_OK;
   }
 
diff --git a/c/driver/framework/utility.cc b/c/driver/framework/utility.cc
new file mode 100644
index 000000000..cbcd8bb54
--- /dev/null
+++ b/c/driver/framework/utility.cc
@@ -0,0 +1,179 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#include "driver/framework/utility.h"
+
+#include <string>
+#include <vector>
+
+#include "arrow-adbc/adbc.h"
+#include "nanoarrow/nanoarrow.hpp"
+
+namespace adbc::driver {
+
+void MakeEmptyStream(ArrowSchema* schema, ArrowArrayStream* out) {
+  nanoarrow::EmptyArrayStream(schema).ToArrayStream(out);
+}
+
+void MakeArrayStream(ArrowSchema* schema, ArrowArray* array, ArrowArrayStream* 
out) {
+  if (array->length == 0) {
+    ArrowArrayRelease(array);
+    std::memset(array, 0, sizeof(ArrowArray));
+
+    MakeEmptyStream(schema, out);
+  } else {
+    nanoarrow::VectorArrayStream(schema, array).ToArrayStream(out);
+  }
+}
+
+Status MakeTableTypesStream(const std::vector<std::string>& table_types,
+                            ArrowArrayStream* out) {
+  nanoarrow::UniqueArray array;
+  nanoarrow::UniqueSchema schema;
+  ArrowSchemaInit(schema.get());
+
+  UNWRAP_ERRNO(Internal, ArrowSchemaSetType(schema.get(), 
NANOARROW_TYPE_STRUCT));
+  UNWRAP_ERRNO(Internal, ArrowSchemaAllocateChildren(schema.get(), 
/*num_columns=*/1));
+  ArrowSchemaInit(schema.get()->children[0]);
+  UNWRAP_ERRNO(Internal,
+               ArrowSchemaSetType(schema.get()->children[0], 
NANOARROW_TYPE_STRING));
+  UNWRAP_ERRNO(Internal, ArrowSchemaSetName(schema.get()->children[0], 
"table_type"));
+  schema.get()->children[0]->flags &= ~ARROW_FLAG_NULLABLE;
+
+  UNWRAP_ERRNO(Internal, ArrowArrayInitFromSchema(array.get(), schema.get(), 
NULL));
+  UNWRAP_ERRNO(Internal, ArrowArrayStartAppending(array.get()));
+
+  for (std::string const& table_type : table_types) {
+    UNWRAP_ERRNO(Internal, ArrowArrayAppendString(array->children[0],
+                                                  
ArrowCharView(table_type.c_str())));
+    UNWRAP_ERRNO(Internal, ArrowArrayFinishElement(array.get()));
+  }
+
+  UNWRAP_ERRNO(Internal, ArrowArrayFinishBuildingDefault(array.get(), 
nullptr));
+  MakeArrayStream(schema.get(), array.get(), out);
+  return status::Ok();
+}
+
+namespace {
+Status MakeGetInfoInit(ArrowSchema* schema, ArrowArray* array) {
+  ArrowSchemaInit(schema);
+  UNWRAP_ERRNO(Internal, ArrowSchemaSetTypeStruct(schema, /*num_columns=*/2));
+
+  UNWRAP_ERRNO(Internal, ArrowSchemaSetType(schema->children[0], 
NANOARROW_TYPE_UINT32));
+  UNWRAP_ERRNO(Internal, ArrowSchemaSetName(schema->children[0], "info_name"));
+  schema->children[0]->flags &= ~ARROW_FLAG_NULLABLE;
+
+  ArrowSchema* info_value = schema->children[1];
+  UNWRAP_ERRNO(Internal,
+               ArrowSchemaSetTypeUnion(info_value, NANOARROW_TYPE_DENSE_UNION, 
6));
+  UNWRAP_ERRNO(Internal, ArrowSchemaSetName(info_value, "info_value"));
+
+  UNWRAP_ERRNO(Internal,
+               ArrowSchemaSetType(info_value->children[0], 
NANOARROW_TYPE_STRING));
+  UNWRAP_ERRNO(Internal, ArrowSchemaSetName(info_value->children[0], 
"string_value"));
+  UNWRAP_ERRNO(Internal,
+               ArrowSchemaSetType(info_value->children[1], 
NANOARROW_TYPE_BOOL));
+  UNWRAP_ERRNO(Internal, ArrowSchemaSetName(info_value->children[1], 
"bool_value"));
+  UNWRAP_ERRNO(Internal,
+               ArrowSchemaSetType(info_value->children[2], 
NANOARROW_TYPE_INT64));
+  UNWRAP_ERRNO(Internal, ArrowSchemaSetName(info_value->children[2], 
"int64_value"));
+  UNWRAP_ERRNO(Internal,
+               ArrowSchemaSetType(info_value->children[3], 
NANOARROW_TYPE_INT32));
+  UNWRAP_ERRNO(Internal, ArrowSchemaSetName(info_value->children[3], 
"int32_bitmask"));
+  UNWRAP_ERRNO(Internal,
+               ArrowSchemaSetType(info_value->children[4], 
NANOARROW_TYPE_LIST));
+  UNWRAP_ERRNO(Internal, ArrowSchemaSetName(info_value->children[4], 
"string_list"));
+  UNWRAP_ERRNO(Internal, ArrowSchemaSetType(info_value->children[5], 
NANOARROW_TYPE_MAP));
+  UNWRAP_ERRNO(Internal,
+               ArrowSchemaSetName(info_value->children[5], 
"int32_to_int32_list_map"));
+
+  UNWRAP_ERRNO(Internal, 
ArrowSchemaSetType(info_value->children[4]->children[0],
+                                            NANOARROW_TYPE_STRING));
+
+  UNWRAP_ERRNO(Internal,
+               
ArrowSchemaSetType(info_value->children[5]->children[0]->children[0],
+                                  NANOARROW_TYPE_INT32));
+  info_value->children[5]->children[0]->children[0]->flags &= 
~ARROW_FLAG_NULLABLE;
+  UNWRAP_ERRNO(Internal,
+               
ArrowSchemaSetType(info_value->children[5]->children[0]->children[1],
+                                  NANOARROW_TYPE_LIST));
+  UNWRAP_ERRNO(
+      Internal,
+      
ArrowSchemaSetType(info_value->children[5]->children[0]->children[1]->children[0],
+                         NANOARROW_TYPE_INT32));
+
+  UNWRAP_ERRNO(Internal, ArrowArrayInitFromSchema(array, schema, nullptr));
+  UNWRAP_ERRNO(Internal, ArrowArrayStartAppending(array));
+
+  return status::Ok();
+}
+
+Status MakeGetInfoAppendString(ArrowArray* array, uint32_t info_code,
+                               std::string_view info_value) {
+  UNWRAP_ERRNO(Internal, ArrowArrayAppendUInt(array->children[0], info_code));
+  // Append to type variant
+  ArrowStringView value;
+  value.data = info_value.data();
+  value.size_bytes = static_cast<int64_t>(info_value.size());
+  UNWRAP_ERRNO(Internal, 
ArrowArrayAppendString(array->children[1]->children[0], value));
+  // Append type code/offset
+  UNWRAP_ERRNO(Internal, ArrowArrayFinishUnionElement(array->children[1], 
/*type_id=*/0));
+  return status::Ok();
+}
+
+Status MakeGetInfoAppendInt(ArrowArray* array, uint32_t info_code, int64_t 
info_value) {
+  UNWRAP_ERRNO(Internal, ArrowArrayAppendUInt(array->children[0], info_code));
+  // Append to type variant
+  UNWRAP_ERRNO(Internal,
+               ArrowArrayAppendInt(array->children[1]->children[2], 
info_value));
+  // Append type code/offset
+  UNWRAP_ERRNO(Internal, ArrowArrayFinishUnionElement(array->children[1], 
/*type_id=*/2));
+  return status::Ok();
+}
+}  // namespace
+
+Status MakeGetInfoStream(const std::vector<InfoValue>& infos, 
ArrowArrayStream* out) {
+  nanoarrow::UniqueSchema schema;
+  nanoarrow::UniqueArray array;
+
+  UNWRAP_STATUS(MakeGetInfoInit(schema.get(), array.get()));
+
+  for (const auto& info : infos) {
+    UNWRAP_STATUS(std::visit(
+        [&](auto&& value) -> Status {
+          using T = std::decay_t<decltype(value)>;
+          if constexpr (std::is_same_v<T, std::string>) {
+            return MakeGetInfoAppendString(array.get(), info.code, value);
+          } else if constexpr (std::is_same_v<T, int64_t>) {
+            return MakeGetInfoAppendInt(array.get(), info.code, value);
+          } else {
+            static_assert(!sizeof(T), "info value type not implemented");
+          }
+          return status::Ok();
+        },
+        info.value));
+    UNWRAP_ERRNO(Internal, ArrowArrayFinishElement(array.get()));
+  }
+
+  ArrowError na_error = {0};
+  UNWRAP_NANOARROW(na_error, Internal,
+                   ArrowArrayFinishBuildingDefault(array.get(), &na_error));
+  MakeArrayStream(schema.get(), array.get(), out);
+  return status::Ok();
+}
+
+}  // namespace adbc::driver
diff --git a/c/driver/framework/utility.h b/c/driver/framework/utility.h
new file mode 100644
index 000000000..af60594ea
--- /dev/null
+++ b/c/driver/framework/utility.h
@@ -0,0 +1,73 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#pragma once
+
+#include <string>
+#include <utility>
+#include <vector>
+
+#include <arrow-adbc/adbc.h>
+
+#include "driver/framework/status.h"
+
+namespace adbc::driver {
+
+/// \brief Create an ArrowArrayStream with zero batches from a given 
ArrowSchema.
+/// \ingroup adbc-framework-catalog
+///
+/// This function takes ownership of schema; the caller is responsible for
+/// releasing out.
+void MakeEmptyStream(ArrowSchema* schema, ArrowArrayStream* out);
+
+/// \brief Create an ArrowArrayStream from a given ArrowSchema and ArrowArray.
+/// \ingroup adbc-framework-catalog
+///
+/// The resulting ArrowArrayStream will contain zero batches if the length of 
the
+/// array is zero, or exactly one batch if the length of the array is non-zero.
+/// This function takes ownership of schema and array; the caller is 
responsible for
+/// releasing out.
+void MakeArrayStream(ArrowSchema* schema, ArrowArray* array, ArrowArrayStream* 
out);
+
+/// \brief Create an ArrowArrayStream representation of a vector of table 
types.
+/// \ingroup adbc-framework-catalog
+///
+/// Create an ArrowArrayStream representation of an array of table types
+/// that can be used to implement AdbcConnectionGetTableTypes(). The caller is 
responsible
+/// for releasing out on success.
+Status MakeTableTypesStream(const std::vector<std::string>& table_types,
+                            ArrowArrayStream* out);
+
+/// \brief Representation of a single item in an array to be returned
+/// from AdbcConnectionGetInfo().
+/// \ingroup adbc-framework-catalog
+struct InfoValue {
+  uint32_t code;
+  std::variant<std::string, int64_t> value;
+
+  InfoValue(uint32_t code, std::variant<std::string, int64_t> value)
+      : code(code), value(std::move(value)) {}
+  InfoValue(uint32_t code, const char* value) : InfoValue(code, 
std::string(value)) {}
+};
+
+/// \brief Create an ArrowArrayStream to be returned from 
AdbcConnectionGetInfo().
+/// \ingroup adbc-framework-catalog
+///
+/// The caller is responsible for releasing out on success.
+Status MakeGetInfoStream(const std::vector<InfoValue>& infos, 
ArrowArrayStream* out);
+
+}  // namespace adbc::driver
diff --git a/c/driver/postgresql/connection.cc 
b/c/driver/postgresql/connection.cc
index b5c0ef161..7b5bb9791 100644
--- a/c/driver/postgresql/connection.cc
+++ b/c/driver/postgresql/connection.cc
@@ -33,7 +33,8 @@
 
 #include "database.h"
 #include "driver/common/utils.h"
-#include "driver/framework/catalog.h"
+#include "driver/framework/objects.h"
+#include "driver/framework/utility.h"
 #include "error.h"
 #include "result_helper.h"
 
@@ -109,7 +110,7 @@ class PqGetObjectsHelper {
 
  private:
   AdbcStatusCode InitArrowArray() {
-    
RAISE_ADBC(adbc::driver::AdbcInitConnectionObjectsSchema(schema_).ToAdbc(error_));
+    RAISE_ADBC(adbc::driver::MakeGetObjectsSchema(schema_).ToAdbc(error_));
 
     CHECK_NA_DETAIL(INTERNAL, ArrowArrayInitFromSchema(array_, schema_, 
&na_error_),
                     &na_error_, error_);
@@ -634,17 +635,22 @@ AdbcStatusCode PostgresConnection::Commit(struct 
AdbcError* error) {
   return ADBC_STATUS_OK;
 }
 
-AdbcStatusCode PostgresConnection::PostgresConnectionGetInfoImpl(
-    const uint32_t* info_codes, size_t info_codes_length, struct ArrowSchema* 
schema,
-    struct ArrowArray* array, struct AdbcError* error) {
-  RAISE_ADBC(adbc::driver::AdbcInitConnectionGetInfoSchema(schema, 
array).ToAdbc(error));
+AdbcStatusCode PostgresConnection::GetInfo(struct AdbcConnection* connection,
+                                           const uint32_t* info_codes,
+                                           size_t info_codes_length,
+                                           struct ArrowArrayStream* out,
+                                           struct AdbcError* error) {
+  if (!info_codes) {
+    info_codes = kSupportedInfoCodes;
+    info_codes_length = sizeof(kSupportedInfoCodes) / 
sizeof(kSupportedInfoCodes[0]);
+  }
+
+  std::vector<adbc::driver::InfoValue> infos;
 
   for (size_t i = 0; i < info_codes_length; i++) {
     switch (info_codes[i]) {
       case ADBC_INFO_VENDOR_NAME:
-        RAISE_ADBC(adbc::driver::AdbcConnectionGetInfoAppendString(array, 
info_codes[i],
-                                                                   
"PostgreSQL")
-                       .ToAdbc(error));
+        infos.push_back({info_codes[i], "PostgreSQL"});
         break;
       case ADBC_INFO_VENDOR_VERSION: {
         const char* stmt = "SHOW server_version_num";
@@ -656,73 +662,32 @@ AdbcStatusCode 
PostgresConnection::PostgresConnectionGetInfoImpl(
           return ADBC_STATUS_INTERNAL;
         }
         const char* server_version_num = (*it)[0].data;
-
-        RAISE_ADBC(adbc::driver::AdbcConnectionGetInfoAppendString(array, 
info_codes[i],
-                                                                   
server_version_num)
-                       .ToAdbc(error));
+        infos.push_back({info_codes[i], server_version_num});
         break;
       }
       case ADBC_INFO_DRIVER_NAME:
-        RAISE_ADBC(adbc::driver::AdbcConnectionGetInfoAppendString(
-                       array, info_codes[i], "ADBC PostgreSQL Driver")
-                       .ToAdbc(error));
+        infos.push_back({info_codes[i], "ADBC PostgreSQL Driver"});
         break;
       case ADBC_INFO_DRIVER_VERSION:
         // TODO(lidavidm): fill in driver version
-        RAISE_ADBC(adbc::driver::AdbcConnectionGetInfoAppendString(array, 
info_codes[i],
-                                                                   "(unknown)")
-                       .ToAdbc(error));
+        infos.push_back({info_codes[i], "(unknown)"});
         break;
       case ADBC_INFO_DRIVER_ARROW_VERSION:
-        RAISE_ADBC(adbc::driver::AdbcConnectionGetInfoAppendString(array, 
info_codes[i],
-                                                                   
NANOARROW_VERSION)
-                       .ToAdbc(error));
+        infos.push_back({info_codes[i], NANOARROW_VERSION});
         break;
       case ADBC_INFO_DRIVER_ADBC_VERSION:
-        RAISE_ADBC(adbc::driver::AdbcConnectionGetInfoAppendInt(array, 
info_codes[i],
-                                                                
ADBC_VERSION_1_1_0)
-                       .ToAdbc(error));
+        infos.push_back({info_codes[i], ADBC_VERSION_1_1_0});
         break;
       default:
         // Ignore
         continue;
     }
-    CHECK_NA(INTERNAL, ArrowArrayFinishElement(array), error);
   }
 
-  struct ArrowError na_error = {0};
-  CHECK_NA_DETAIL(INTERNAL, ArrowArrayFinishBuildingDefault(array, &na_error), 
&na_error,
-                  error);
-
+  RAISE_ADBC(adbc::driver::MakeGetInfoStream(infos, out).ToAdbc(error));
   return ADBC_STATUS_OK;
 }
 
-AdbcStatusCode PostgresConnection::GetInfo(struct AdbcConnection* connection,
-                                           const uint32_t* info_codes,
-                                           size_t info_codes_length,
-                                           struct ArrowArrayStream* out,
-                                           struct AdbcError* error) {
-  if (!info_codes) {
-    info_codes = kSupportedInfoCodes;
-    info_codes_length = sizeof(kSupportedInfoCodes) / 
sizeof(kSupportedInfoCodes[0]);
-  }
-
-  struct ArrowSchema schema;
-  std::memset(&schema, 0, sizeof(schema));
-  struct ArrowArray array;
-  std::memset(&array, 0, sizeof(array));
-
-  AdbcStatusCode status = PostgresConnectionGetInfoImpl(info_codes, 
info_codes_length,
-                                                        &schema, &array, 
error);
-  if (status != ADBC_STATUS_OK) {
-    if (schema.release) schema.release(&schema);
-    if (array.release) array.release(&array);
-    return status;
-  }
-
-  return BatchToArrayStream(&array, &schema, out, error);
-}
-
 AdbcStatusCode PostgresConnection::GetObjects(
     struct AdbcConnection* connection, int depth, const char* catalog,
     const char* db_schema, const char* table_name, const char** table_types,
@@ -743,7 +708,8 @@ AdbcStatusCode PostgresConnection::GetObjects(
     return status;
   }
 
-  return BatchToArrayStream(&array, &schema, out, error);
+  adbc::driver::MakeArrayStream(&schema, &array, out);
+  return ADBC_STATUS_OK;
 }
 
 AdbcStatusCode PostgresConnection::GetOption(const char* option, char* value,
@@ -1076,7 +1042,8 @@ AdbcStatusCode PostgresConnection::GetStatistics(const 
char* catalog,
     return status;
   }
 
-  return BatchToArrayStream(&array, &schema, out, error);
+  adbc::driver::MakeArrayStream(&schema, &array, out);
+  return ADBC_STATUS_OK;
 }
 
 AdbcStatusCode PostgresConnectionGetStatisticNamesImpl(struct ArrowSchema* 
schema,
@@ -1125,7 +1092,9 @@ AdbcStatusCode 
PostgresConnection::GetStatisticNames(struct ArrowArrayStream* ou
     if (array.release) array.release(&array);
     return status;
   }
-  return BatchToArrayStream(&array, &schema, out, error);
+
+  adbc::driver::MakeArrayStream(&schema, &array, out);
+  return ADBC_STATUS_OK;
 }
 
 AdbcStatusCode PostgresConnection::GetTableSchema(const char* catalog,
@@ -1195,54 +1164,17 @@ AdbcStatusCode PostgresConnection::GetTableSchema(const 
char* catalog,
   return final_status;
 }
 
-AdbcStatusCode PostgresConnectionGetTableTypesImpl(struct ArrowSchema* schema,
-                                                   struct ArrowArray* array,
-                                                   struct AdbcError* error) {
-  // See 'relkind' in 
https://www.postgresql.org/docs/current/catalog-pg-class.html
-  auto uschema = nanoarrow::UniqueSchema();
-  ArrowSchemaInit(uschema.get());
-
-  CHECK_NA(INTERNAL, ArrowSchemaSetType(uschema.get(), NANOARROW_TYPE_STRUCT), 
error);
-  CHECK_NA(INTERNAL, ArrowSchemaAllocateChildren(uschema.get(), 
/*num_columns=*/1),
-           error);
-  ArrowSchemaInit(uschema.get()->children[0]);
-  CHECK_NA(INTERNAL,
-           ArrowSchemaSetType(uschema.get()->children[0], 
NANOARROW_TYPE_STRING), error);
-  CHECK_NA(INTERNAL, ArrowSchemaSetName(uschema.get()->children[0], 
"table_type"), error);
-  uschema.get()->children[0]->flags &= ~ARROW_FLAG_NULLABLE;
-
-  CHECK_NA(INTERNAL, ArrowArrayInitFromSchema(array, uschema.get(), NULL), 
error);
-  CHECK_NA(INTERNAL, ArrowArrayStartAppending(array), error);
-
-  for (auto const& table_type : kPgTableTypes) {
-    CHECK_NA(INTERNAL,
-             ArrowArrayAppendString(array->children[0],
-                                    ArrowCharView(table_type.first.c_str())),
-             error);
-    CHECK_NA(INTERNAL, ArrowArrayFinishElement(array), error);
-  }
-
-  CHECK_NA(INTERNAL, ArrowArrayFinishBuildingDefault(array, NULL), error);
-
-  uschema.move(schema);
-  return ADBC_STATUS_OK;
-}
-
 AdbcStatusCode PostgresConnection::GetTableTypes(struct AdbcConnection* 
connection,
                                                  struct ArrowArrayStream* out,
                                                  struct AdbcError* error) {
-  struct ArrowSchema schema;
-  std::memset(&schema, 0, sizeof(schema));
-  struct ArrowArray array;
-  std::memset(&array, 0, sizeof(array));
-
-  AdbcStatusCode status = PostgresConnectionGetTableTypesImpl(&schema, &array, 
error);
-  if (status != ADBC_STATUS_OK) {
-    if (schema.release) schema.release(&schema);
-    if (array.release) array.release(&array);
-    return status;
+  std::vector<std::string> table_types;
+  table_types.reserve(kPgTableTypes.size());
+  for (auto const& table_type : kPgTableTypes) {
+    table_types.push_back(table_type.first);
   }
-  return BatchToArrayStream(&array, &schema, out, error);
+
+  RAISE_STATUS(error, adbc::driver::MakeTableTypesStream(table_types, out));
+  return ADBC_STATUS_OK;
 }
 
 AdbcStatusCode PostgresConnection::Init(struct AdbcDatabase* database,
diff --git a/c/driver/postgresql/connection.h b/c/driver/postgresql/connection.h
index 2a3b59c5c..787a7dcda 100644
--- a/c/driver/postgresql/connection.h
+++ b/c/driver/postgresql/connection.h
@@ -75,11 +75,6 @@ class PostgresConnection {
   bool autocommit() const { return autocommit_; }
 
  private:
-  AdbcStatusCode PostgresConnectionGetInfoImpl(const uint32_t* info_codes,
-                                               size_t info_codes_length,
-                                               struct ArrowSchema* schema,
-                                               struct ArrowArray* array,
-                                               struct AdbcError* error);
   std::shared_ptr<PostgresDatabase> database_;
   std::shared_ptr<PostgresTypeResolver> type_resolver_;
   PGconn* conn_;
diff --git a/c/driver/postgresql/statement.cc b/c/driver/postgresql/statement.cc
index d86f775b3..c5252b7db 100644
--- a/c/driver/postgresql/statement.cc
+++ b/c/driver/postgresql/statement.cc
@@ -40,6 +40,7 @@
 #include "connection.h"
 #include "driver/common/options.h"
 #include "driver/common/utils.h"
+#include "driver/framework/utility.h"
 #include "error.h"
 #include "postgres_type.h"
 #include "postgres_util.h"
@@ -296,7 +297,7 @@ AdbcStatusCode PostgresStatement::Bind(struct ArrowArray* 
values,
 
   if (bind_.release) bind_.release(&bind_);
   // Make a one-value stream
-  nanoarrow::VectorArrayStream(schema, values).ToArrayStream(&bind_);
+  adbc::driver::MakeArrayStream(schema, values, &bind_);
   return ADBC_STATUS_OK;
 }
 
diff --git a/c/driver/sqlite/sqlite.cc b/c/driver/sqlite/sqlite.cc
index 207b591f3..c6277fb62 100644
--- a/c/driver/sqlite/sqlite.cc
+++ b/c/driver/sqlite/sqlite.cc
@@ -15,19 +15,14 @@
 // specific language governing permissions and limitations
 // under the License.
 
-#include <cstdarg>
 #include <limits>
 
 #include <arrow-adbc/adbc.h>
-#include <nanoarrow/nanoarrow.h>
 #include <sqlite3.h>
 #include <nanoarrow/nanoarrow.hpp>
 
 #define ADBC_FRAMEWORK_USE_FMT
-#include "driver/common/options.h"
-#include "driver/common/utils.h"
 #include "driver/framework/base_driver.h"
-#include "driver/framework/catalog.h"
 #include "driver/framework/connection.h"
 #include "driver/framework/database.h"
 #include "driver/framework/statement.h"
@@ -934,21 +929,25 @@ class SqliteStatement : public 
driver::Statement<SqliteStatement> {
     }
     assert(stmt != nullptr);
 
-    AdbcStatusCode status = ADBC_STATUS_OK;
+    AdbcStatusCode status_code = ADBC_STATUS_OK;
+    Status status = status::Ok();
     struct AdbcError error = ADBC_ERROR_INIT;
     while (true) {
       char finished = 0;
-      status = AdbcSqliteBinderBindNext(&binder_, conn_, stmt, &finished, 
&error);
-      if (status != ADBC_STATUS_OK || finished) break;
+      status_code = AdbcSqliteBinderBindNext(&binder_, conn_, stmt, &finished, 
&error);
+      if (status_code != ADBC_STATUS_OK || finished) {
+        status = Status::FromAdbc(status_code, error);
+        break;
+      }
 
       int rc = 0;
       do {
         rc = sqlite3_step(stmt);
       } while (rc == SQLITE_ROW);
       if (rc != SQLITE_DONE) {
-        SetError(&error, "failed to execute: %s\nquery was: %s", 
sqlite3_errmsg(conn_),
-                 insert.data());
-        status = ADBC_STATUS_INTERNAL;
+        status = status::fmt::Internal("failed to execute: {}\nquery was: {}",
+                                       sqlite3_errmsg(conn_), insert.data());
+        status_code = ADBC_STATUS_INTERNAL;
         break;
       }
       row_count++;
@@ -956,15 +955,15 @@ class SqliteStatement : public 
driver::Statement<SqliteStatement> {
     std::ignore = sqlite3_finalize(stmt);
 
     if (is_autocommit) {
-      if (status == ADBC_STATUS_OK) {
+      if (status_code == ADBC_STATUS_OK) {
         UNWRAP_STATUS(::adbc::sqlite::SqliteQuery::Execute(conn_, "COMMIT"));
       } else {
         UNWRAP_STATUS(::adbc::sqlite::SqliteQuery::Execute(conn_, "ROLLBACK"));
       }
     }
 
-    if (status != ADBC_STATUS_OK) {
-      return Status::FromAdbc(status, error);
+    if (status_code != ADBC_STATUS_OK) {
+      return status;
     }
     return row_count;
   }
diff --git a/c/driver/sqlite/sqlite_test.cc b/c/driver/sqlite/sqlite_test.cc
index d644b6827..e053e8725 100644
--- a/c/driver/sqlite/sqlite_test.cc
+++ b/c/driver/sqlite/sqlite_test.cc
@@ -445,8 +445,11 @@ class SqliteReaderTest : public ::testing::Test {
   }
 
   void Bind(struct ArrowArray* batch, struct ArrowSchema* schema) {
-    ASSERT_THAT(AdbcSqliteBinderSetArray(&binder, batch, schema, &error),
-                IsOkStatus(&error));
+    Handle<struct ArrowArrayStream> stream;
+    struct ArrowArray batch_internal = *batch;
+    batch->release = nullptr;
+    adbc_validation::MakeStream(&stream.value, schema, {batch_internal});
+    ASSERT_NO_FATAL_FAILURE(Bind(&stream.value));
   }
 
   void Bind(struct ArrowArrayStream* stream) {
diff --git a/c/driver/sqlite/statement_reader.c 
b/c/driver/sqlite/statement_reader.c
index dc036a963..97a134a99 100644
--- a/c/driver/sqlite/statement_reader.c
+++ b/c/driver/sqlite/statement_reader.c
@@ -105,14 +105,6 @@ AdbcStatusCode AdbcSqliteBinderSet(struct 
AdbcSqliteBinder* binder,
   return ADBC_STATUS_OK;
 }
 
-AdbcStatusCode AdbcSqliteBinderSetArray(struct AdbcSqliteBinder* binder,
-                                        struct ArrowArray* values,
-                                        struct ArrowSchema* schema,
-                                        struct AdbcError* error) {
-  AdbcSqliteBinderRelease(binder);
-  RAISE_ADBC(BatchToArrayStream(values, schema, &binder->params, error));
-  return AdbcSqliteBinderSet(binder, error);
-}  // NOLINT(whitespace/indent)
 AdbcStatusCode AdbcSqliteBinderSetArrayStream(struct AdbcSqliteBinder* binder,
                                               struct ArrowArrayStream* values,
                                               struct AdbcError* error) {
diff --git a/c/driver/sqlite/statement_reader.h 
b/c/driver/sqlite/statement_reader.h
index 77333a990..2e6b19086 100644
--- a/c/driver/sqlite/statement_reader.h
+++ b/c/driver/sqlite/statement_reader.h
@@ -40,11 +40,6 @@ struct ADBC_EXPORT AdbcSqliteBinder {
   int64_t next_row;
 };
 
-ADBC_EXPORT
-AdbcStatusCode AdbcSqliteBinderSetArray(struct AdbcSqliteBinder* binder,
-                                        struct ArrowArray* values,
-                                        struct ArrowSchema* schema,
-                                        struct AdbcError* error);
 ADBC_EXPORT
 AdbcStatusCode AdbcSqliteBinderSetArrayStream(struct AdbcSqliteBinder* binder,
                                               struct ArrowArrayStream* values,
diff --git a/go/adbc/drivermgr/wrapper_sqlite_test.go 
b/go/adbc/drivermgr/wrapper_sqlite_test.go
index f531d36f6..9b4f509a3 100644
--- a/go/adbc/drivermgr/wrapper_sqlite_test.go
+++ b/go/adbc/drivermgr/wrapper_sqlite_test.go
@@ -190,10 +190,6 @@ func (dm *DriverMgrSuite) TestGetObjectsCatalog() {
 
        expSchema := adbc.GetObjectsSchema
        dm.True(expSchema.Equal(rdr.Schema()))
-       dm.True(rdr.Next())
-
-       rec := rdr.Record()
-       dm.Equal(int64(0), rec.NumRows())
        dm.False(rdr.Next())
 }
 
diff --git a/r/adbcpostgresql/src/Makevars.in b/r/adbcpostgresql/src/Makevars.in
index 4c2af03bf..be1b87253 100644
--- a/r/adbcpostgresql/src/Makevars.in
+++ b/r/adbcpostgresql/src/Makevars.in
@@ -21,7 +21,8 @@ PKG_LIBS=@libs@
 
 OBJECTS = init.o \
     c/driver/common/utils.o \
-    c/driver/framework/catalog.o \
+    c/driver/framework/objects.o \
+    c/driver/framework/utility.o \
     c/driver/postgresql/connection.o \
     c/driver/postgresql/database.o \
     c/driver/postgresql/error.o \
diff --git a/r/adbcpostgresql/src/Makevars.ucrt 
b/r/adbcpostgresql/src/Makevars.ucrt
index 659829dae..275fa4025 100644
--- a/r/adbcpostgresql/src/Makevars.ucrt
+++ b/r/adbcpostgresql/src/Makevars.ucrt
@@ -22,7 +22,8 @@ PKG_LIBS = -lpq -lpgcommon -lpgport -lssl -lcrypto -lz 
-lsecur32 -lws2_32 -lwlda
 
 OBJECTS = init.o \
     c/driver/common/utils.o \
-    c/driver/framework/catalog.o \
+    c/driver/framework/objects.o \
+    c/driver/framework/utility.o \
     c/driver/postgresql/connection.o \
     c/driver/postgresql/database.o \
     c/driver/postgresql/error.o \
diff --git a/r/adbcpostgresql/src/Makevars.win 
b/r/adbcpostgresql/src/Makevars.win
index 2cf926913..1937905cc 100644
--- a/r/adbcpostgresql/src/Makevars.win
+++ b/r/adbcpostgresql/src/Makevars.win
@@ -24,7 +24,8 @@ PKG_LIBS = -L$(RWINLIB)/lib${R_ARCH}${CRT} \
 
 OBJECTS = init.o \
     c/driver/common/utils.o \
-    c/driver/framework/catalog.o \
+    c/driver/framework/objects.o \
+    c/driver/framework/utility.o \
     c/driver/postgresql/connection.o \
     c/driver/postgresql/database.o \
     c/driver/postgresql/error.o \
diff --git a/r/adbcsqlite/src/Makevars.in b/r/adbcsqlite/src/Makevars.in
index 93a1ce7b4..ab27b1ff1 100644
--- a/r/adbcsqlite/src/Makevars.in
+++ b/r/adbcsqlite/src/Makevars.in
@@ -21,8 +21,8 @@ PKG_LIBS=@libs@
 
 OBJECTS = init.o \
     c/driver/common/utils.o \
-    c/driver/framework/catalog.o \
     c/driver/framework/objects.o \
+    c/driver/framework/utility.o \
     c/driver/sqlite/sqlite.o \
     c/driver/sqlite/statement_reader.o \
     c/vendor/nanoarrow/nanoarrow.o \

Reply via email to