From: Richard Guo Date: Wed, 3 Jun 2026 00:36:52 +0000 (+0900) Subject: Fix wrong unsafe-flag test in check_output_expressions() X-Git-Url: http://git.ipfire.org/gitweb/index.cgi?a=commitdiff_plain;h=ad1cb0d08df765d671abd624e284ebbab790c804;p=thirdparty%2Fpostgresql.git Fix wrong unsafe-flag test in check_output_expressions() The check for window functions (point 4) guarded on the wrong bit: it tested UNSAFE_NOTIN_DISTINCTON_CLAUSE while setting UNSAFE_NOTIN_PARTITIONBY_CLAUSE. Each check in this loop guards on the same bit it is about to set, as an idempotency optimization, since unsafeFlags[] is accumulated across the arms of a set operation and there is no point recomputing a column's status once its bit is present. This is not a live bug. When UNSAFE_NOTIN_PARTITIONBY_CLAUSE is already set but UNSAFE_NOTIN_DISTINCTON_CLAUSE is not, the guard fails to skip targetIsInAllPartitionLists() and recomputes it, but setting the same bit again changes nothing. When UNSAFE_NOTIN_DISTINCTON_CLAUSE is already set, point 4 is skipped and UNSAFE_NOTIN_PARTITIONBY_CLAUSE is left unset; but such a column is already unsafe for pushdown via UNSAFE_NOTIN_DISTINCTON_CLAUSE, so the outcome is unchanged. To fix, test UNSAFE_NOTIN_PARTITIONBY_CLAUSE, matching the bit being set and the pattern of the surrounding checks. Back-patch to v15, where the buggy check was introduced. Author: Richard Guo Reviewed-by: Tender Wang Reviewed-by: David Rowley Discussion: https://postgr.es/m/CAMbWs49Q_xnF_P2QSUyDzJ34MnrO7dh-cUAaK2HJPgSgh88NcA@mail.gmail.com Backpatch-through: 15 --- diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c index f75e0f99cb9..f105582d5e1 100644 --- a/src/backend/optimizer/path/allpaths.c +++ b/src/backend/optimizer/path/allpaths.c @@ -3755,7 +3755,7 @@ check_output_expressions(Query *subquery, pushdown_safety_info *safetyInfo) /* If subquery uses window functions, check point 4 */ if (subquery->hasWindowFuncs && (safetyInfo->unsafeFlags[tle->resno] & - UNSAFE_NOTIN_DISTINCTON_CLAUSE) == 0 && + UNSAFE_NOTIN_PARTITIONBY_CLAUSE) == 0 && !targetIsInAllPartitionLists(tle, subquery)) { /* not present in all PARTITION BY clauses, so mark it unsafe */