diff --git a/contrib/pg_overexplain/expected/pg_overexplain.out b/contrib/pg_overexplain/expected/pg_overexplain.out
index 05c6686d677..12ab92629ab 100644
--- a/contrib/pg_overexplain/expected/pg_overexplain.out
+++ b/contrib/pg_overexplain/expected/pg_overexplain.out
@@ -294,13 +294,131 @@ $$);
false +
false +
+
- 1 3 4 +
- none +
+
+ 1 3 4 +
+ none +
+
(1 row)
+-- Test JSON format with RANGE_TABLE to verify valid JSON structure.
+SELECT explain_filter($$
+EXPLAIN (RANGE_TABLE, FORMAT JSON, COSTS OFF)
+SELECT genus, array_agg(name ORDER BY name) FROM vegetables GROUP BY genus
+$$);
+ explain_filter
+----------------------------------------------------------------
+ [ +
+ { +
+ "Plan": { +
+ "Node Type": "Aggregate", +
+ "Strategy": "Sorted", +
+ "Partial Mode": "Simple", +
+ "Parallel Aware": false, +
+ "Async Capable": false, +
+ "Disabled": false, +
+ "Group Key": ["vegetables.genus"], +
+ "Plans": [ +
+ { +
+ "Node Type": "Sort", +
+ "Parent Relationship": "Outer", +
+ "Parallel Aware": false, +
+ "Async Capable": false, +
+ "Disabled": false, +
+ "Sort Key": ["vegetables.genus", "vegetables.name"],+
+ "Plans": [ +
+ { +
+ "Node Type": "Append", +
+ "Parent Relationship": "Outer", +
+ "Parallel Aware": false, +
+ "Async Capable": false, +
+ "Disabled": false, +
+ "Append RTIs": "1", +
+ "Child Append RTIs": "none", +
+ "Subplans Removed": 0, +
+ "Plans": [ +
+ { +
+ "Node Type": "Seq Scan", +
+ "Parent Relationship": "Member", +
+ "Parallel Aware": false, +
+ "Async Capable": false, +
+ "Relation Name": "brassica", +
+ "Alias": "vegetables_1", +
+ "Disabled": false, +
+ "Scan RTI": 3 +
+ }, +
+ { +
+ "Node Type": "Seq Scan", +
+ "Parent Relationship": "Member", +
+ "Parallel Aware": false, +
+ "Async Capable": false, +
+ "Relation Name": "daucus", +
+ "Alias": "vegetables_2", +
+ "Disabled": false, +
+ "Scan RTI": 4 +
+ } +
+ ] +
+ } +
+ ] +
+ } +
+ ] +
+ }, +
+ "Range Table": [ +
+ { +
+ "RTI": 1, +
+ "Kind": "relation", +
+ "Inherited": true, +
+ "In From Clause": true, +
+ "Eref": "vegetables (id, name, genus)", +
+ "Relation": "vegetables", +
+ "Relation Kind": "partitioned_table", +
+ "Relation Lock Mode": "AccessShareLock", +
+ "Permission Info Index": 1, +
+ "Security Barrier": false, +
+ "Lateral": false +
+ }, +
+ { +
+ "RTI": 2, +
+ "Kind": "group", +
+ "Inherited": false, +
+ "In From Clause": false, +
+ "Eref": "\"*GROUP*\" (genus)", +
+ "Security Barrier": false, +
+ "Lateral": false +
+ }, +
+ { +
+ "RTI": 3, +
+ "Kind": "relation", +
+ "Inherited": false, +
+ "In From Clause": true, +
+ "Alias": "vegetables (id, name, genus)", +
+ "Eref": "vegetables (id, name, genus)", +
+ "Relation": "brassica", +
+ "Relation Kind": "relation", +
+ "Relation Lock Mode": "AccessShareLock", +
+ "Security Barrier": false, +
+ "Lateral": false +
+ }, +
+ { +
+ "RTI": 4, +
+ "Kind": "relation", +
+ "Inherited": false, +
+ "In From Clause": true, +
+ "Alias": "vegetables (id, name, genus)", +
+ "Eref": "vegetables (id, name, genus)", +
+ "Relation": "daucus", +
+ "Relation Kind": "relation", +
+ "Relation Lock Mode": "AccessShareLock", +
+ "Security Barrier": false, +
+ "Lateral": false +
+ } +
+ ], +
+ "Unprunable RTIs": "1 3 4", +
+ "Result RTIs": "none" +
+ } +
+ ]
+(1 row)
+
-- Test just the DEBUG option. Verify that it shows information about
-- disabled nodes, parallel safety, and the parallelModeNeeded flag.
SET enable_seqscan = false;
diff --git a/contrib/pg_overexplain/pg_overexplain.c b/contrib/pg_overexplain/pg_overexplain.c
index 715eda8dc56..fb277e02308 100644
--- a/contrib/pg_overexplain/pg_overexplain.c
+++ b/contrib/pg_overexplain/pg_overexplain.c
@@ -776,7 +776,14 @@ overexplain_range_table(PlannedStmt *plannedstmt, ExplainState *es)
ExplainCloseGroup("Range Table Entry", NULL, true, es);
}
- /* Print PlannedStmt fields that contain RTIs. */
+ /* Close the Range Table array before emitting PlannedStmt-level fields. */
+ ExplainCloseGroup("Range Table", "Range Table", false, es);
+
+ /*
+ * Print PlannedStmt fields that contain RTIs. These are properties of
+ * the PlannedStmt, not of individual RTEs, so they belong outside the
+ * Range Table array.
+ */
if (es->format != EXPLAIN_FORMAT_TEXT ||
!bms_is_empty(plannedstmt->unprunableRelids))
overexplain_bitmapset("Unprunable RTIs", plannedstmt->unprunableRelids,
@@ -785,9 +792,6 @@ overexplain_range_table(PlannedStmt *plannedstmt, ExplainState *es)
!bms_is_empty(plannedstmt->resultRelationRelids))
overexplain_bitmapset("Result RTIs", plannedstmt->resultRelationRelids,
es);
-
- /* Close group, we're all done */
- ExplainCloseGroup("Range Table", "Range Table", false, es);
}
/*
diff --git a/contrib/pg_overexplain/sql/pg_overexplain.sql b/contrib/pg_overexplain/sql/pg_overexplain.sql
index d07f93688a9..3f17b61a2da 100644
--- a/contrib/pg_overexplain/sql/pg_overexplain.sql
+++ b/contrib/pg_overexplain/sql/pg_overexplain.sql
@@ -66,6 +66,12 @@ EXPLAIN (DEBUG, RANGE_TABLE, FORMAT XML, COSTS OFF)
SELECT genus, array_agg(name ORDER BY name) FROM vegetables GROUP BY genus
$$);
+-- Test JSON format with RANGE_TABLE to verify valid JSON structure.
+SELECT explain_filter($$
+EXPLAIN (RANGE_TABLE, FORMAT JSON, COSTS OFF)
+SELECT genus, array_agg(name ORDER BY name) FROM vegetables GROUP BY genus
+$$);
+
-- Test just the DEBUG option. Verify that it shows information about
-- disabled nodes, parallel safety, and the parallelModeNeeded flag.
SET enable_seqscan = false;