Hi all,

During a recent review of 911e70207703 for a different issue, it has
come up to me (and also Tom, in CC) that the following functions are
marked as not strict (core backend or contrib/):
brin_bloom_options
brin_minmax_multi_options
gtsvector_options
ghstore_options
gtrgm_options
g_int_options
g_intbig_options
_ltree_gist_options
ltree_gist_options 

However, if one looks at the internals of any of these functions, it
is easy to note that they are not able to handle NULL inputs at all,
leading to a crash (aka 8f7e35b08ad5).  It looks like a mistake to me
to declare them as not STRICT, while their internals are written to
not be able to handle NULL.

Most of these functions are in contrib/, and it feels overengineered
to bump the modules just to mark these functions as STRICT, so I
propose to have them do nothing if given a NULL input instead.  The
three opclass option functions in core can be flipped more easily in
pg_proc.dat.

Comments or opinions?
--
Michael
From c21c762a7182bc49626a58b68370d281dec10c18 Mon Sep 17 00:00:00 2001
From: Michael Paquier <[email protected]>
Date: Mon, 17 Aug 2026 16:50:54 +0900
Subject: [PATCH] Fix handling of NULL input in opclass option functions

Nine opclass option functions exist in the tree, and are not marked as
STRICT while they are unable to handle NULL inputs:
1) Backend core:
brin_bloom_options
brin_minmax_multi_options
gtsvector_options
2) Contrib modules:
ghstore_options
gtrgm_options
g_int_options
g_intbig_options
_ltree_gist_options
ltree_gist_options

The backend core functions have their proisstrict switched to true.  The
contrib module functions do nothing if given a NULL input.

Oversights originating from 911e70207703, with a coding pattern that has
spread across more places of the tree.
---
 src/include/catalog/pg_proc.dat | 6 +++---
 contrib/hstore/hstore_gist.c    | 7 ++++++-
 contrib/intarray/_int_gist.c    | 7 ++++++-
 contrib/intarray/_intbig_gist.c | 7 ++++++-
 contrib/ltree/_ltree_gist.c     | 7 ++++++-
 contrib/ltree/ltree_gist.c      | 7 ++++++-
 contrib/pg_trgm/trgm_gist.c     | 7 ++++++-
 7 files changed, 39 insertions(+), 9 deletions(-)

diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index 66c3c9a04cfb..5e998183bdb1 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -9131,7 +9131,7 @@
   proargtypes => 'internal internal internal',
   prosrc => 'brin_minmax_multi_union' },
 { oid => '4620', descr => 'BRIN multi minmax support',
-  proname => 'brin_minmax_multi_options', proisstrict => 'f',
+  proname => 'brin_minmax_multi_options', proisstrict => 't',
   prorettype => 'void', proargtypes => 'internal',
   prosrc => 'brin_minmax_multi_options' },
 
@@ -9237,7 +9237,7 @@
   proname => 'brin_bloom_union', prorettype => 'bool',
   proargtypes => 'internal internal internal', prosrc => 'brin_bloom_union' },
 { oid => '4595', descr => 'BRIN bloom support',
-  proname => 'brin_bloom_options', proisstrict => 'f', prorettype => 'void',
+  proname => 'brin_bloom_options', proisstrict => 't', prorettype => 'void',
   proargtypes => 'internal', prosrc => 'brin_bloom_options' },
 
 # userlock replacements
@@ -10008,7 +10008,7 @@
   proargtypes => 'internal gtsvector int4 oid internal',
   prosrc => 'gtsvector_consistent_oldsig' },
 { oid => '3434', descr => 'GiST tsvector support',
-  proname => 'gtsvector_options', proisstrict => 'f', prorettype => 'void',
+  proname => 'gtsvector_options', proisstrict => 't', prorettype => 'void',
   proargtypes => 'internal', prosrc => 'gtsvector_options' },
 
 { oid => '3656', descr => 'GIN tsvector support',
diff --git a/contrib/hstore/hstore_gist.c b/contrib/hstore/hstore_gist.c
index 832a268e0d2f..9bb29a6ed111 100644
--- a/contrib/hstore/hstore_gist.c
+++ b/contrib/hstore/hstore_gist.c
@@ -614,7 +614,12 @@ ghstore_consistent(PG_FUNCTION_ARGS)
 Datum
 ghstore_options(PG_FUNCTION_ARGS)
 {
-       local_relopts *relopts = (local_relopts *) PG_GETARG_POINTER(0);
+       local_relopts *relopts;
+
+       if (PG_ARGISNULL(0))
+               PG_RETURN_VOID();
+
+       relopts = (local_relopts *) PG_GETARG_POINTER(0);
 
        init_local_reloptions(relopts, sizeof(GistHstoreOptions));
        add_local_int_reloption(relopts, "siglen",
diff --git a/contrib/intarray/_int_gist.c b/contrib/intarray/_int_gist.c
index 98711ac54e2f..d602a5ac8067 100644
--- a/contrib/intarray/_int_gist.c
+++ b/contrib/intarray/_int_gist.c
@@ -626,7 +626,12 @@ g_int_picksplit(PG_FUNCTION_ARGS)
 Datum
 g_int_options(PG_FUNCTION_ARGS)
 {
-       local_relopts *relopts = (local_relopts *) PG_GETARG_POINTER(0);
+       local_relopts *relopts;
+
+       if (PG_ARGISNULL(0))
+               PG_RETURN_VOID();
+
+       relopts = (local_relopts *) PG_GETARG_POINTER(0);
 
        init_local_reloptions(relopts, sizeof(GISTIntArrayOptions));
        add_local_int_reloption(relopts, "numranges",
diff --git a/contrib/intarray/_intbig_gist.c b/contrib/intarray/_intbig_gist.c
index 396da703438e..5f570f263ff8 100644
--- a/contrib/intarray/_intbig_gist.c
+++ b/contrib/intarray/_intbig_gist.c
@@ -585,7 +585,12 @@ g_intbig_consistent(PG_FUNCTION_ARGS)
 Datum
 g_intbig_options(PG_FUNCTION_ARGS)
 {
-       local_relopts *relopts = (local_relopts *) PG_GETARG_POINTER(0);
+       local_relopts *relopts;
+
+       if (PG_ARGISNULL(0))
+               PG_RETURN_VOID();
+
+       relopts = (local_relopts *) PG_GETARG_POINTER(0);
 
        init_local_reloptions(relopts, sizeof(GISTIntArrayBigOptions));
        add_local_int_reloption(relopts, "siglen",
diff --git a/contrib/ltree/_ltree_gist.c b/contrib/ltree/_ltree_gist.c
index 07d668235924..77e5aa852343 100644
--- a/contrib/ltree/_ltree_gist.c
+++ b/contrib/ltree/_ltree_gist.c
@@ -546,7 +546,12 @@ _ltree_consistent(PG_FUNCTION_ARGS)
 Datum
 _ltree_gist_options(PG_FUNCTION_ARGS)
 {
-       local_relopts *relopts = (local_relopts *) PG_GETARG_POINTER(0);
+       local_relopts *relopts;
+
+       if (PG_ARGISNULL(0))
+               PG_RETURN_VOID();
+
+       relopts = (local_relopts *) PG_GETARG_POINTER(0);
 
        init_local_reloptions(relopts, sizeof(LtreeGistOptions));
        add_local_int_reloption(relopts, "siglen", "signature length",
diff --git a/contrib/ltree/ltree_gist.c b/contrib/ltree/ltree_gist.c
index e8451171c729..bb39b4cb973d 100644
--- a/contrib/ltree/ltree_gist.c
+++ b/contrib/ltree/ltree_gist.c
@@ -735,7 +735,12 @@ ltree_gist_relopts_validator(void *parsed_options, 
relopt_value *vals,
 Datum
 ltree_gist_options(PG_FUNCTION_ARGS)
 {
-       local_relopts *relopts = (local_relopts *) PG_GETARG_POINTER(0);
+       local_relopts *relopts;
+
+       if (PG_ARGISNULL(0))
+               PG_RETURN_VOID();
+
+       relopts = (local_relopts *) PG_GETARG_POINTER(0);
 
        init_local_reloptions(relopts, sizeof(LtreeGistOptions));
        add_local_int_reloption(relopts, "siglen",
diff --git a/contrib/pg_trgm/trgm_gist.c b/contrib/pg_trgm/trgm_gist.c
index 42d0b7a5d65f..f43aafb1f524 100644
--- a/contrib/pg_trgm/trgm_gist.c
+++ b/contrib/pg_trgm/trgm_gist.c
@@ -963,7 +963,12 @@ gtrgm_picksplit(PG_FUNCTION_ARGS)
 Datum
 gtrgm_options(PG_FUNCTION_ARGS)
 {
-       local_relopts *relopts = (local_relopts *) PG_GETARG_POINTER(0);
+       local_relopts *relopts;
+
+       if (PG_ARGISNULL(0))
+               PG_RETURN_VOID();
+
+       relopts = (local_relopts *) PG_GETARG_POINTER(0);
 
        init_local_reloptions(relopts, sizeof(TrgmGistOptions));
        add_local_int_reloption(relopts, "siglen",
-- 
2.55.0

Attachment: signature.asc
Description: PGP signature

Reply via email to