From 211c60619de14d3f9973d38c8c64be4016d4ff92 Mon Sep 17 00:00:00 2001
From: Tomas Vondra <tomas@vondra.me>
Date: Fri, 19 Jun 2026 19:05:27 +0200
Subject: [PATCH v1 2/6] Count joinrels constructed by standard_join_search

Instruments standard_join_search and join_search_one_level to count the
join rels constructed, and writes the count to the server log. This is
the same quantity calculated by the DPccp estimator, so this is useful
as a cross-check and for information how accurate is the estimate
---
 src/backend/optimizer/path/allpaths.c |  7 ++++++-
 src/backend/optimizer/path/joinrels.c | 10 +++++++++-
 src/include/optimizer/paths.h         |  2 +-
 3 files changed, 16 insertions(+), 3 deletions(-)

diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index c134594a21a..2792b729b72 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -3950,6 +3950,8 @@ standard_join_search(PlannerInfo *root, int levels_needed, List *initial_rels)
 	int			lev;
 	RelOptInfo *rel;
 
+	int		standard_join_count = 0;
+
 	/*
 	 * This function cannot be invoked recursively within any one planning
 	 * problem, so join_rel_level[] can't be in use already.
@@ -3980,7 +3982,7 @@ standard_join_search(PlannerInfo *root, int levels_needed, List *initial_rels)
 		 * level, and build paths for making each one from every available
 		 * pair of lower-level relations.
 		 */
-		join_search_one_level(root, lev);
+		standard_join_count += join_search_one_level(root, lev);
 
 		/*
 		 * Run generate_partitionwise_join_paths() and
@@ -4052,6 +4054,9 @@ standard_join_search(PlannerInfo *root, int levels_needed, List *initial_rels)
 
 	root->join_rel_level = NULL;
 
+	elog(WARNING, "standard_join_search rels %d count %d",
+		 list_length(initial_rels), standard_join_count);
+
 	return rel;
 }
 
diff --git a/src/backend/optimizer/path/joinrels.c b/src/backend/optimizer/path/joinrels.c
index 443e2dca7c0..f4ef3984023 100644
--- a/src/backend/optimizer/path/joinrels.c
+++ b/src/backend/optimizer/path/joinrels.c
@@ -60,6 +60,7 @@ static void get_matching_part_pairs(PlannerInfo *root, RelOptInfo *joinrel,
 									RelOptInfo *rel1, RelOptInfo *rel2,
 									List **parts1, List **parts2);
 
+static int join_search_level_count;
 
 /*
  * join_search_one_level
@@ -74,7 +75,7 @@ static void get_matching_part_pairs(PlannerInfo *root, RelOptInfo *joinrel,
  *
  * The result is returned in root->join_rel_level[level].
  */
-void
+int
 join_search_one_level(PlannerInfo *root, int level)
 {
 	List	  **joinrels = root->join_rel_level;
@@ -86,6 +87,8 @@ join_search_one_level(PlannerInfo *root, int level)
 	/* Set join_cur_level so that new joinrels are added to proper list */
 	root->join_cur_level = level;
 
+	join_search_level_count = 0;
+
 	/*
 	 * First, consider left-sided and right-sided plans, in which rels of
 	 * exactly level-1 member relations are joined against initial relations.
@@ -196,6 +199,7 @@ join_search_one_level(PlannerInfo *root, int level)
 						have_join_order_restriction(root, old_rel, new_rel))
 					{
 						(void) make_join_rel(root, old_rel, new_rel);
+						join_search_level_count++;
 					}
 				}
 			}
@@ -259,6 +263,8 @@ join_search_one_level(PlannerInfo *root, int level)
 			!root->hasLateralRTEs)
 			elog(ERROR, "failed to build any %d-way joins", level);
 	}
+
+	return join_search_level_count;
 }
 
 /*
@@ -298,6 +304,7 @@ make_rels_by_clause_joins(PlannerInfo *root,
 			 have_join_order_restriction(root, old_rel, other_rel)))
 		{
 			(void) make_join_rel(root, old_rel, other_rel);
+			join_search_level_count++;
 		}
 	}
 }
@@ -329,6 +336,7 @@ make_rels_by_clauseless_joins(PlannerInfo *root,
 		if (!bms_overlap(other_rel->relids, old_rel->relids))
 		{
 			(void) make_join_rel(root, old_rel, other_rel);
+			join_search_level_count++;
 		}
 	}
 }
diff --git a/src/include/optimizer/paths.h b/src/include/optimizer/paths.h
index 9401860ccb3..c021e7e6ada 100644
--- a/src/include/optimizer/paths.h
+++ b/src/include/optimizer/paths.h
@@ -112,7 +112,7 @@ extern void add_paths_to_joinrel(PlannerInfo *root, RelOptInfo *joinrel,
  * joinrels.c
  *	  routines to determine which relations to join
  */
-extern void join_search_one_level(PlannerInfo *root, int level);
+extern int join_search_one_level(PlannerInfo *root, int level);
 extern RelOptInfo *make_join_rel(PlannerInfo *root,
 								 RelOptInfo *rel1, RelOptInfo *rel2);
 extern Relids add_outer_joins_to_relids(PlannerInfo *root, Relids input_relids,
-- 
2.54.0

