Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1wUUgW-001CMc-00 for pgsql-bugs@arkaria.postgresql.org; Tue, 02 Jun 2026 19:21:56 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.96) (envelope-from ) id 1wUUgU-00FpJ6-2f for pgsql-bugs@arkaria.postgresql.org; Tue, 02 Jun 2026 19:21:54 +0000 Received: from magus.postgresql.org ([2a02:c0:301:0:ffff::29]) by malur.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1wUUgU-00FpIy-1p for pgsql-bugs@lists.postgresql.org; Tue, 02 Jun 2026 19:21:54 +0000 Received: from sss.pgh.pa.us ([68.162.161.243]) by magus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.98.2) (envelope-from ) id 1wUUgS-00000000uiu-0V6S for pgsql-bugs@lists.postgresql.org; Tue, 02 Jun 2026 19:21:54 +0000 Received: from sss1.sss.pgh.pa.us (localhost [127.0.0.1]) by sss.pgh.pa.us (8.18.1/8.18.1) with ESMTP id 652JLjWi2949987; Tue, 2 Jun 2026 15:21:45 -0400 From: Tom Lane To: Mats Rydberg cc: pgsql-bugs@lists.postgresql.org Subject: Re: GREATEST/LEAST ignores comparison operator volatility in contain_volatile_functions_walker In-reply-to: References: Comments: In-reply-to Mats Rydberg message dated "Tue, 02 Jun 2026 10:48:32 +0200" MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-ID: <2949985.1780428105.1@sss.pgh.pa.us> Date: Tue, 02 Jun 2026 15:21:45 -0400 Message-ID: <2949986.1780428105@sss.pgh.pa.us> List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk Mats Rydberg writes: > GREATEST and LEAST (MinMaxExpr nodes) are missing from > contain_volatile_functions_walker in src/backend/optimizer/util/clauses.c. > OpExpr nodes are correctly handled -- the walker resolves the oprcode via > set_opfuncid and checks func_volatile. But there is no MinMaxExpr case, so > GREATEST/LEAST always appears function-free to the volatility checker > regardless of the < or > operator's provolatile. This is intentional, per the comment in contain_mutable_functions_walker (which contain_volatile_functions_walker refers to): * It should be safe to treat MinMaxExpr as immutable, because it will * depend on a non-cross-type btree comparison function, and those should * always be immutable. A non-cross-type btree comparison function directly determines the ordering of an index for its data type, so if it isn't immutable then you can't rely on the index to be consistent. > The practical consequence: a GREATEST/LEAST expression whose comparison > operator is STABLE or VOLATILE is incorrectly treated as IMMUTABLE. The > reproducer below demonstrates this via a generated column, which requires > an IMMUTABLE expression. PostgreSQL accepts the column definition when it > should reject it. This reproducer depends on an invalid operator class. The reason why you can't make an operator class without superuser privilege is that the system depends on them behaving per spec. We'd try to enforce that rather than just assume it, were it not for the halting problem. regards, tom lane