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;
}