From 21481f60bcb8ab71f225e9387a9d85be6cae516a Mon Sep 17 00:00:00 2001 From: Terry Ng Date: Thu, 21 Aug 2025 22:17:46 -0400 Subject: [PATCH 1/3] Increase recursion limit --- sqlx-postgres/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sqlx-postgres/src/lib.rs b/sqlx-postgres/src/lib.rs index f68c928881..cddbe8aaef 100644 --- a/sqlx-postgres/src/lib.rs +++ b/sqlx-postgres/src/lib.rs @@ -1,5 +1,5 @@ //! **PostgreSQL** database driver. - +#![recursion_limit = "512"] // or "512" if still overflows #[macro_use] extern crate sqlx_core; From 3707c6fadc7ffc7feea9b45ab0c027dde9ac150b Mon Sep 17 00:00:00 2001 From: Terry Ng Date: Thu, 21 Aug 2025 22:40:57 -0400 Subject: [PATCH 2/3] Make fetch_type_by_oid a non-async function returning a boxed future; remove the ad-hoc boxing site. --- sqlx-postgres/src/connection/describe.rs | 120 +++++++++++------------ 1 file changed, 58 insertions(+), 62 deletions(-) diff --git a/sqlx-postgres/src/connection/describe.rs b/sqlx-postgres/src/connection/describe.rs index dfe5286458..769b561373 100644 --- a/sqlx-postgres/src/connection/describe.rs +++ b/sqlx-postgres/src/connection/describe.rs @@ -182,8 +182,8 @@ impl PgConnection { // fallback to asking the database directly for a type name if should_fetch { - // we're boxing this future here so we can use async recursion - let info = Box::pin(async { self.fetch_type_by_oid(oid).await }).await?; + // recursion now boxed inside fetch_type_by_oid() + let info = self.fetch_type_by_oid(oid).await?; // cache the type name <-> oid relationship in a paired hashmap // so we don't come down this road again @@ -267,70 +267,66 @@ impl PgConnection { })) } - async fn fetch_type_by_oid(&mut self, oid: Oid) -> Result { - let (name, typ_type, category, relation_id, element, base_type): ( - String, - i8, - i8, - Oid, - Oid, - Oid, - ) = query_as( - // Converting the OID to `regtype` and then `text` will give us the name that - // the type will need to be found at by search_path. - "SELECT oid::regtype::text, \ - typtype, \ - typcategory, \ - typrelid, \ - typelem, \ - typbasetype \ - FROM pg_catalog.pg_type \ - WHERE oid = $1", - ) - .bind(oid) - .fetch_one(&mut *self) - .await?; - - let typ_type = TypType::try_from(typ_type); - let category = TypCategory::try_from(category); - - match (typ_type, category) { - (Ok(TypType::Domain), _) => self.fetch_domain_by_oid(oid, base_type, name).await, - - (Ok(TypType::Base), Ok(TypCategory::Array)) => { - Ok(PgTypeInfo(PgType::Custom(Arc::new(PgCustomType { - kind: PgTypeKind::Array( - self.maybe_fetch_type_info_by_oid(element, true).await?, - ), - name: name.into(), - oid, - })))) - } + fn fetch_type_by_oid(&mut self, oid: Oid) -> BoxFuture<'_, Result> { + Box::pin(async move { + let (name, typ_type, category, relation_id, element, base_type): ( + String, + i8, + i8, + Oid, + Oid, + Oid, + ) = query_as( + "SELECT oid::regtype::text, \ + typtype, \ + typcategory, \ + typrelid, \ + typelem, \ + typbasetype \ + FROM pg_catalog.pg_type \ + WHERE oid = $1", + ) + .bind(oid) + .fetch_one(&mut *self) + .await?; - (Ok(TypType::Pseudo), Ok(TypCategory::Pseudo)) => { - Ok(PgTypeInfo(PgType::Custom(Arc::new(PgCustomType { - kind: PgTypeKind::Pseudo, + let typ_type = TypType::try_from(typ_type); + let category = TypCategory::try_from(category); + + match (typ_type, category) { + (Ok(TypType::Domain), _) => self.fetch_domain_by_oid(oid, base_type, name).await, + (Ok(TypType::Base), Ok(TypCategory::Array)) => Ok(PgTypeInfo(PgType::Custom(Arc::new( + PgCustomType { + kind: PgTypeKind::Array( + self.maybe_fetch_type_info_by_oid(element, true).await?, + ), + name: name.into(), + oid, + }, + )))), + (Ok(TypType::Pseudo), Ok(TypCategory::Pseudo)) => Ok(PgTypeInfo(PgType::Custom( + Arc::new(PgCustomType { + kind: PgTypeKind::Pseudo, + name: name.into(), + oid, + }), + ))), + (Ok(TypType::Range), Ok(TypCategory::Range)) => { + self.fetch_range_by_oid(oid, name).await + } + (Ok(TypType::Enum), Ok(TypCategory::Enum)) => { + self.fetch_enum_by_oid(oid, name).await + } + (Ok(TypType::Composite), Ok(TypCategory::Composite)) => { + self.fetch_composite_by_oid(oid, relation_id, name).await + } + _ => Ok(PgTypeInfo(PgType::Custom(Arc::new(PgCustomType { + kind: PgTypeKind::Simple, name: name.into(), oid, - })))) - } - - (Ok(TypType::Range), Ok(TypCategory::Range)) => { - self.fetch_range_by_oid(oid, name).await + })))), } - - (Ok(TypType::Enum), Ok(TypCategory::Enum)) => self.fetch_enum_by_oid(oid, name).await, - - (Ok(TypType::Composite), Ok(TypCategory::Composite)) => { - self.fetch_composite_by_oid(oid, relation_id, name).await - } - - _ => Ok(PgTypeInfo(PgType::Custom(Arc::new(PgCustomType { - kind: PgTypeKind::Simple, - name: name.into(), - oid, - })))), - } + }) } async fn fetch_enum_by_oid(&mut self, oid: Oid, name: String) -> Result { From 117aa07527828fc6fda5a44024b68776fe057d3d Mon Sep 17 00:00:00 2001 From: Terry Ng Date: Mon, 25 Aug 2025 10:24:57 -0400 Subject: [PATCH 3/3] feat: add BoxFuture import to describe.rs for future compatibility --- sqlx-postgres/src/connection/describe.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/sqlx-postgres/src/connection/describe.rs b/sqlx-postgres/src/connection/describe.rs index 769b561373..6fe656e63a 100644 --- a/sqlx-postgres/src/connection/describe.rs +++ b/sqlx-postgres/src/connection/describe.rs @@ -16,6 +16,7 @@ use sqlx_core::column::{ColumnOrigin, TableColumn}; use sqlx_core::query_builder::QueryBuilder; use sqlx_core::sql_str::AssertSqlSafe; use std::sync::Arc; +use futures_core::future::BoxFuture; /// Describes the type of the `pg_type.typtype` column ///