From a8928b26e1c35ec1cea99a3405d927e86efdfbf3 Mon Sep 17 00:00:00 2001 From: shihao zhong Date: Sat, 24 Oct 2026 00:27:53 -0400 Subject: [PATCH] Keep initial tuple hash table within hash_mem, skip it for EXPLAIN simplehash rounds nbuckets / SH_FILLFACTOR up to a power of 2, so the hash_mem cap in BuildTupleHashTable could still give an empty bucket array of twice hash_mem. Halve the limit, as nodeAgg.c does. Also skip building the table in ExecInitSetOp and ExecInitRecursiveUnion for EXPLAIN without ANALYZE, as nodeAgg.c does since 2cccb627f10. --- src/backend/executor/execGrouping.c | 7 ++++++- src/backend/executor/nodeRecursiveunion.c | 4 +++- src/backend/executor/nodeSetOp.c | 4 +++- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/backend/executor/execGrouping.c b/src/backend/executor/execGrouping.c index 9aaced19759..714067b4630 100644 --- a/src/backend/executor/execGrouping.c +++ b/src/backend/executor/execGrouping.c @@ -227,8 +227,13 @@ BuildTupleHashTable(PlanState *parent, else nbuckets = (uint32) nelements; + /* + * simplehash rounds nelements / SH_FILLFACTOR up to a power of 2, so + * the bucket array can be twice what we ask for. Halve the limit to + * keep the initial table within hash_mem, as nodeAgg.c does. + */ entrysize = sizeof(TupleHashEntryData) + additionalsize; - hash_mem_limit = get_hash_memory_limit() / entrysize; + hash_mem_limit = get_hash_memory_limit() / entrysize / 2; if (nbuckets > hash_mem_limit) nbuckets = hash_mem_limit; } diff --git a/src/backend/executor/nodeRecursiveunion.c b/src/backend/executor/nodeRecursiveunion.c index 7166397e59b..5f2cdb57134 100644 --- a/src/backend/executor/nodeRecursiveunion.c +++ b/src/backend/executor/nodeRecursiveunion.c @@ -270,7 +270,9 @@ ExecInitRecursiveUnion(RecursiveUnion *node, EState *estate, int eflags) node->dupOperators, &rustate->eqfuncoids, &rustate->hashfunctions); - build_hash_table(rustate); + /* Skip massive memory allocation if we are just doing EXPLAIN */ + if (!(eflags & EXEC_FLAG_EXPLAIN_ONLY)) + build_hash_table(rustate); } return rustate; diff --git a/src/backend/executor/nodeSetOp.c b/src/backend/executor/nodeSetOp.c index 88815259b34..0dcbb60c15c 100644 --- a/src/backend/executor/nodeSetOp.c +++ b/src/backend/executor/nodeSetOp.c @@ -673,7 +673,9 @@ ExecInitSetOp(SetOp *node, EState *estate, int eflags) /* Create a hash table if needed */ if (node->strategy == SETOP_HASHED) { - build_hash_table(setopstate); + /* Skip massive memory allocation if we are just doing EXPLAIN */ + if (!(eflags & EXEC_FLAG_EXPLAIN_ONLY)) + build_hash_table(setopstate); setopstate->table_filled = false; } -- 2.37.1 (Apple Git-137.1)