[PATCH] Replace COUNT(NULL) with '0'::bigint

Started by Junwang Zhaoabout 2 hours ago1 messages
#1Junwang Zhao
zhjwpku@gmail.com
1 attachment(s)

Hi,

In [1]/messages/by-id/CAApHDvrde9DUpQ3DhPd3ia9tchVmhZqewfzxSYWmYFWVj=LPpg@mail.gmail.com, David Rowley noted that COUNT(NULL) can be replaced
with '0'::bigint. The change should be straightforward, and I came
up with the attached patch to implement it.

[1]: /messages/by-id/CAApHDvrde9DUpQ3DhPd3ia9tchVmhZqewfzxSYWmYFWVj=LPpg@mail.gmail.com

--
Regards
Junwang Zhao

Attachments:

0001-Replace-COUNT-NULL-with-0-bigint.patchapplication/octet-stream; name=0001-Replace-COUNT-NULL-with-0-bigint.patchDownload
From 98c46bd8a6138e6dba4f55f35e2d719c5c80ee15 Mon Sep 17 00:00:00 2001
From: Junwang Zhao <zhjwpku@gmail.com>
Date: Sun, 25 Jan 2026 14:16:58 +0800
Subject: [PATCH] Replace COUNT(NULL) with '0'::bigint

When count() receives a constant NULL argument, replace it with
'0'::bigint constant instead of leaving it as NULL.
---
 src/backend/utils/adt/int8.c             | 16 ++++++++++++++++
 src/test/regress/expected/aggregates.out | 15 +++++++--------
 src/test/regress/sql/aggregates.sql      |  2 +-
 3 files changed, 24 insertions(+), 9 deletions(-)

diff --git a/src/backend/utils/adt/int8.c b/src/backend/utils/adt/int8.c
index 37d34685b93..438733684bd 100644
--- a/src/backend/utils/adt/int8.c
+++ b/src/backend/utils/adt/int8.c
@@ -20,6 +20,7 @@
 #include "common/int.h"
 #include "funcapi.h"
 #include "libpq/pqformat.h"
+#include "nodes/makefuncs.h"
 #include "nodes/nodeFuncs.h"
 #include "nodes/supportnodes.h"
 #include "optimizer/optimizer.h"
@@ -855,6 +856,21 @@ int8inc_support(PG_FUNCTION_ARGS)
 
 				PG_RETURN_POINTER(newagg);
 			}
+
+			/* Replace constant NULL argument with '0'::bigint */
+			if (IsA(arg, Const) && ((Const *) arg)->constisnull)
+			{
+				Const	   *newconst;
+
+				newconst = makeConst(INT8OID,
+									 -1,
+									 InvalidOid,
+									 sizeof(int64),
+									 Int64GetDatum(0),
+									 false,
+									 true);
+				PG_RETURN_POINTER(newconst);
+			}
 		}
 	}
 
diff --git a/src/test/regress/expected/aggregates.out b/src/test/regress/expected/aggregates.out
index cae8e7bca31..ef15e994e3f 100644
--- a/src/test/regress/expected/aggregates.out
+++ b/src/test/regress/expected/aggregates.out
@@ -2922,16 +2922,15 @@ select count('bananas') from agg_simplify;
          Output: a, not_null_col, nullable_col
 (4 rows)
 
--- Ensure count(null) isn't optimized
+-- Ensure count(null) is replaced with '0'::bigint
 explain (costs off, verbose)
 select count(null) from agg_simplify;
-                  QUERY PLAN                   
------------------------------------------------
- Aggregate
-   Output: count(NULL::unknown)
-   ->  Seq Scan on public.agg_simplify
-         Output: a, not_null_col, nullable_col
-(4 rows)
+         QUERY PLAN          
+-----------------------------
+ Result
+   Output: '0'::bigint
+   Replaces: MinMaxAggregate
+(3 rows)
 
 -- Ensure count(nullable_col) does not use count(*)
 explain (costs off, verbose)
diff --git a/src/test/regress/sql/aggregates.sql b/src/test/regress/sql/aggregates.sql
index 850f5a5787f..34990a09823 100644
--- a/src/test/regress/sql/aggregates.sql
+++ b/src/test/regress/sql/aggregates.sql
@@ -1145,7 +1145,7 @@ select count(not_null_col) from agg_simplify;
 explain (costs off, verbose)
 select count('bananas') from agg_simplify;
 
--- Ensure count(null) isn't optimized
+-- Ensure count(null) is replaced with '0'::bigint
 explain (costs off, verbose)
 select count(null) from agg_simplify;
 
-- 
2.41.0