diff --git a/src/backend/executor/nodeHash.c b/src/backend/executor/nodeHash.c index 8d2201ab67f..c93e24fccf2 100644 --- a/src/backend/executor/nodeHash.c +++ b/src/backend/executor/nodeHash.c @@ -35,6 +35,7 @@ #include "executor/nodeHash.h" #include "executor/nodeHashjoin.h" #include "miscadmin.h" +#include "optimizer/cost.h" #include "port/pg_bitutils.h" #include "utils/dynahash.h" #include "utils/lsyscache.h" @@ -668,6 +669,7 @@ ExecChooseHashTableSize(double ntuples, int tupwidth, bool useskew, size_t hash_table_bytes; size_t bucket_bytes; size_t max_pointers; + size_t max_batches; int nbatch = 1; int nbuckets; double dbuckets; @@ -775,6 +777,16 @@ ExecChooseHashTableSize(double ntuples, int tupwidth, bool useskew, /* If max_pointers isn't a power of 2, must round it down to one */ max_pointers = pg_prevpower2_size_t(max_pointers); + /* + * Prevent DSA overflow. This is expanded definition of EstimateParallelHashJoinBatch function + * used in ExecParallelHashJoinSetUpBatches: + * dsa_allocate0(hashtable->area, + * EstimateParallelHashJoinBatch(hashtable) * nbatch) + */ + max_batches = MaxAllocSize / (MAXALIGN(sizeof(ParallelHashJoinBatch)) + + MAXALIGN(sts_estimate(max_parallel_workers_per_gather + 1) * 2)); + max_batches = pg_prevpower2_size_t(max_batches); + /* Also ensure we avoid integer overflow in nbatch and nbuckets */ /* (this step is redundant given the current value of MaxAllocSize) */ max_pointers = Min(max_pointers, INT_MAX / 2 + 1); @@ -844,6 +856,7 @@ ExecChooseHashTableSize(double ntuples, int tupwidth, bool useskew, /* Calculate required number of batches. */ dbatch = ceil(inner_rel_bytes / (hash_table_bytes - bucket_bytes)); dbatch = Min(dbatch, max_pointers); + dbatch = Min(dbatch, max_batches); minbatch = (int) dbatch; nbatch = pg_nextpower2_32(Max(2, minbatch)); } @@ -910,7 +923,8 @@ ExecChooseHashTableSize(double ntuples, int tupwidth, bool useskew, * this during the initial sizing - once we start building the hash, * nbucket is fixed. */ - while (nbatch > 0) + while (nbatch > 0 && + nbuckets * 2 <= max_pointers) /* prevent allocation limit overflow */ { /* how much memory are we using with current nbatch value */ size_t current_space = hash_table_bytes + (2 * nbatch * BLCKSZ);