Skip to content

Commit c3f242b

Browse files
committed
WIP fix(postgres): use non-prepared statements for metadata queries (3)
1 parent d18120d commit c3f242b

File tree

1 file changed

+38
-17
lines changed

1 file changed

+38
-17
lines changed

sqlx-postgres/src/connection/resolve.rs

Lines changed: 38 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -612,6 +612,8 @@ impl TypesResolver {
612612
fn push_type(&mut self, original_name: impl Display, oid_expr: impl Display) {
613613
use std::fmt::Write;
614614

615+
tracing::trace!(%original_name, %oid_expr, "push_type");
616+
615617
// Lazily push the preamble to `self.query` so we don't allocate in the fast path
616618
// (all types already known)
617619
if self.query.is_empty() {
@@ -627,9 +629,10 @@ impl TypesResolver {
627629
typbasetype,\n\
628630
rngsubtype,\n\
629631
COALESCE(\
630-
(SELECT array_agg(enumlabel) OVER (ORDER BY enumsortorder)\n\
632+
(SELECT array_agg(enumlabel) FROM (SELECT *\n\
631633
FROM pg_catalog.pg_enum\n\
632-
WHERE enumtypid = pg_type.oid),\n\
634+
WHERE enumtypid = pg_type.oid\n\
635+
ORDER BY enumsortorder)),\n\
633636
'{{}}') enum_labels,\n\
634637
COALESCE(\n\
635638
(SELECT array_agg((attname, atttypid)) FROM (SELECT *\n\
@@ -650,10 +653,16 @@ impl TypesResolver {
650653
}
651654

652655
async fn fill_cache(&mut self, conn: &mut PgConnection) -> Result<(), Error> {
653-
let mut existing_dependencies = HashMap::<Oid, Vec<TypeResolverRow>>::new();
656+
let mut missing_dependencies = HashMap::<Oid, Vec<TypeResolverRow>>::new();
657+
658+
// Iteratively resolve types until all are resolved, or we hit a dead-end.
659+
// We statically cap the number of iterations in case we somehow encounter a circular type
660+
// dependency, which I *assume* Postgres should forbid.
661+
for _ in 0..64 {
662+
if self.query.is_empty() {
663+
break;
664+
}
654665

655-
// Iteratively resolve types until all or resolved or we hit a dead-end
656-
while !self.query.is_empty() {
657666
// * Cancel-safety
658667
// * Makes this type reusable if we want to for whatever reason
659668
// * Avoids an allocation when converting to `SqlStr`
@@ -665,18 +674,26 @@ impl TypesResolver {
665674
LEFT JOIN pg_catalog.pg_range ON pg_type.oid = pg_range.rngtypid",
666675
);
667676

668-
let types = raw_sql(AssertSqlSafe(query)).fetch_all(&mut *conn).await?;
677+
tracing::trace!(?query, "fill_cache");
669678

670-
let mut new_dependencies = HashMap::<Oid, Vec<TypeResolverRow>>::new();
679+
let types = raw_sql(AssertSqlSafe(query)).fetch_all(&mut *conn).await?;
671680

672681
'outer: for row in types {
673682
let mut type_row = TypeResolverRow::from_row(&row)?;
674683

684+
tracing::trace!("type_row: {type_row:?}");
685+
675686
let mut resolved_dependencies = VecDeque::new();
676687

677688
loop {
678689
if let ControlFlow::Break(missing_oid) = conn.try_cache_type(&type_row)? {
679-
new_dependencies
690+
tracing::trace!(
691+
ty_name = type_row.catalog_name,
692+
missing_oid = missing_oid.0,
693+
"type missing dependency"
694+
);
695+
696+
missing_dependencies
680697
.entry(missing_oid)
681698
.or_default()
682699
.push(type_row);
@@ -687,28 +704,32 @@ impl TypesResolver {
687704
}
688705

689706
resolved_dependencies.extend(
690-
existing_dependencies
707+
missing_dependencies
691708
.remove(&type_row.oid)
692709
.unwrap_or_default(),
693710
);
694711

695712
// Iteratively mark existing dependencies as resolved
696713
if let Some(next_row) = resolved_dependencies.pop_back() {
714+
tracing::trace!(
715+
resolved_oid = type_row.oid.0,
716+
ty_name = next_row.catalog_name,
717+
"resolved dependency"
718+
);
719+
697720
type_row = next_row
698721
} else {
699722
break;
700723
}
701724
}
702725
}
726+
}
703727

704-
if !existing_dependencies.is_empty() {
705-
return Err(Error::Protocol(format!(
706-
"unable to resolve type OIDs: {:?}",
707-
existing_dependencies.keys()
708-
)));
709-
}
710-
711-
existing_dependencies = new_dependencies;
728+
if !missing_dependencies.is_empty() {
729+
return Err(Error::Protocol(format!(
730+
"unable to resolve type OIDs: {:?}",
731+
missing_dependencies.keys()
732+
)));
712733
}
713734

714735
Ok(())

0 commit comments

Comments
 (0)