AdbcStatusCode PostgresDatabase::RebuildTypeResolver()

in c/driver/postgresql/database.cc [98:187]


AdbcStatusCode PostgresDatabase::RebuildTypeResolver(struct AdbcError* error) {
  PGconn* conn = nullptr;
  AdbcStatusCode final_status = Connect(&conn, error);
  if (final_status != ADBC_STATUS_OK) {
    return final_status;
  }

  // We need a few queries to build the resolver. The current strategy might
  // fail for some recursive definitions (e.g., arrays of records of arrays).
  // First, one on the pg_attribute table to resolve column names/oids for
  // record types.
  const std::string kColumnsQuery = R"(
SELECT
    attrelid,
    attname,
    atttypid
FROM
    pg_catalog.pg_attribute
ORDER BY
    attrelid, attnum
)";

  // Second, a query of the pg_type table. This query may need a few attempts to handle
  // recursive definitions (e.g., record types with array column). This currently won't
  // handle range types because those rows don't have child OID information. Arrays types
  // are inserted after a successful insert of the element type.
  const std::string kTypeQuery = R"(
SELECT
    oid,
    typname,
    typreceive,
    typbasetype,
    typarray,
    typrelid
FROM
    pg_catalog.pg_type
WHERE
    (typreceive != 0 OR typname = 'aclitem') AND typtype != 'r' AND typreceive::TEXT != 'array_recv'
ORDER BY
    oid
)";

  // Create a new type resolver (this instance's type_resolver_ member
  // will be updated at the end if this succeeds).
  auto resolver = std::make_shared<PostgresTypeResolver>();

  // Insert record type definitions (this includes table schemas)
  pg_result* result = PQexec(conn, kColumnsQuery.c_str());
  ExecStatusType pq_status = PQresultStatus(result);
  if (pq_status == PGRES_TUPLES_OK) {
    InsertPgAttributeResult(result, resolver);
  } else {
    SetError(error, "%s%s",
             "[libpq] Failed to build type mapping table: ", PQerrorMessage(conn));
    final_status = ADBC_STATUS_IO;
  }

  PQclear(result);

  // Attempt filling the resolver a few times to handle recursive definitions.
  int32_t max_attempts = 3;
  for (int32_t i = 0; i < max_attempts; i++) {
    result = PQexec(conn, kTypeQuery.c_str());
    ExecStatusType pq_status = PQresultStatus(result);
    if (pq_status == PGRES_TUPLES_OK) {
      InsertPgTypeResult(result, resolver);
    } else {
      SetError(error, "%s%s",
               "[libpq] Failed to build type mapping table: ", PQerrorMessage(conn));
      final_status = ADBC_STATUS_IO;
    }

    PQclear(result);
    if (final_status != ADBC_STATUS_OK) {
      break;
    }
  }

  // Disconnect since PostgreSQL connections can be heavy.
  {
    AdbcStatusCode status = Disconnect(&conn, error);
    if (status != ADBC_STATUS_OK) final_status = status;
  }

  if (final_status == ADBC_STATUS_OK) {
    type_resolver_ = std::move(resolver);
  }

  return final_status;
}