On 11.06.26 14:56, Tom Lane wrote:
Peter Eisentraut <[email protected]> writes:
This changes the argtypes argument of SPI_prepare(),
SPI_prepare_cursor(), SPI_cursor_open_with_args(), and
SPI_execute_with_args() from Oid *argtypes to const Oid *argtypes.

We've discussed that before, and held off because we weren't entirely
sure if anyone would complain that it is an API/ABI break.  I think
it's quite likely that the libabigail buildfarm machines will say
it is, but is there any actual consequence?

I don't think we are tracking ABI compatibility in unreleased branches?

One related thing I remember being discussed is adding qualifiers to functions that are part of the index or table access method APIs, because that breaks source code compatibility. I don't think that kind of concern applies here. (Also, I think we could still do those kinds of changes, but it'd be better to do them all at once in one release.)

Also, if we are going to use const in SPI, there are more parameters
besides the datatype OIDs that could stand to be const-ified, eg
the various Datum/isnull arrays.

Those were already done, except that there were two curious stragglers, which I've added another patch to fix.
From ad0857ce3c257ddc022ca48d93300d4f9957a489 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <[email protected]>
Date: Sat, 25 Apr 2026 23:44:36 +0200
Subject: [PATCH v2 1/2] Make SPI_prepare argtypes argument const

This changes the argtypes argument of SPI_prepare(),
SPI_prepare_cursor(), SPI_cursor_open_with_args(), and
SPI_execute_with_args() from Oid *argtypes to const Oid *argtypes.
The underlying functions were already receptive to that, so this
doesn't require any significant changes beyond the function signatures
and some internal variables.

Commit 28972b6fc3dc recently introduced a case where a const had to be
cast away before calling these functions.  This is fixed here.
---
 contrib/postgres_fdw/postgres_fdw.c |  6 +++---
 doc/src/sgml/spi.sgml               |  8 ++++----
 src/backend/executor/spi.c          | 26 ++++++++++++++++----------
 src/backend/utils/adt/ri_triggers.c |  4 ++--
 src/backend/utils/cache/plancache.c |  2 +-
 src/include/executor/spi.h          |  8 ++++----
 src/include/executor/spi_priv.h     |  2 +-
 src/include/utils/plancache.h       |  2 +-
 8 files changed, 32 insertions(+), 26 deletions(-)

diff --git a/contrib/postgres_fdw/postgres_fdw.c 
b/contrib/postgres_fdw/postgres_fdw.c
index 0a589f8db74..322212552ee 100644
--- a/contrib/postgres_fdw/postgres_fdw.c
+++ b/contrib/postgres_fdw/postgres_fdw.c
@@ -6164,12 +6164,12 @@ import_fetched_statistics(const char *schemaname,
                Assert(PQntuples(remstats->att) >= 1);
 
                attimport_plan = SPI_prepare(attimport_sql, 
ATTIMPORT_SQL_NUM_FIELDS,
-                                                                        (Oid 
*) attimport_argtypes);
+                                                                        
attimport_argtypes);
                if (attimport_plan == NULL)
                        elog(ERROR, "failed to prepare attimport_sql query");
 
                attclear_plan = SPI_prepare(attclear_sql, 
ATTCLEAR_SQL_NUM_FIELDS,
-                                                                       (Oid *) 
attclear_argtypes);
+                                                                       
attclear_argtypes);
                if (attclear_plan == NULL)
                        elog(ERROR, "failed to prepare attclear_sql query");
 
@@ -6247,7 +6247,7 @@ import_fetched_statistics(const char *schemaname,
 
        spirc = SPI_execute_with_args(relimport_sql,
                                                                  
RELIMPORT_SQL_NUM_FIELDS,
-                                                                 (Oid *) 
relimport_argtypes,
+                                                                 
relimport_argtypes,
                                                                  values, 
nulls, false, 1);
        if (spirc != SPI_OK_SELECT)
                elog(ERROR, "failed to execute relimport_sql query for foreign 
table \"%s.%s\"",
diff --git a/doc/src/sgml/spi.sgml b/doc/src/sgml/spi.sgml
index e30d0962ae7..043c6f00039 100644
--- a/doc/src/sgml/spi.sgml
+++ b/doc/src/sgml/spi.sgml
@@ -845,7 +845,7 @@ <title>Return Value</title>
  <refsynopsisdiv>
 <synopsis>
 int SPI_execute_with_args(const char *<parameter>command</parameter>,
-                          int <parameter>nargs</parameter>, Oid 
*<parameter>argtypes</parameter>,
+                          int <parameter>nargs</parameter>, const Oid 
*<parameter>argtypes</parameter>,
                           const Datum *<parameter>values</parameter>, const 
char *<parameter>nulls</parameter>,
                           bool <parameter>read_only</parameter>, long 
<parameter>count</parameter>)
 </synopsis>
@@ -997,7 +997,7 @@ <title>Return Value</title>
 
  <refsynopsisdiv>
 <synopsis>
-SPIPlanPtr SPI_prepare(const char * <parameter>command</parameter>, int 
<parameter>nargs</parameter>, Oid * <parameter>argtypes</parameter>)
+SPIPlanPtr SPI_prepare(const char * <parameter>command</parameter>, int 
<parameter>nargs</parameter>, const Oid * <parameter>argtypes</parameter>)
 </synopsis>
  </refsynopsisdiv>
 
@@ -1160,7 +1160,7 @@ <title>Notes</title>
  <refsynopsisdiv>
 <synopsis>
 SPIPlanPtr SPI_prepare_cursor(const char * <parameter>command</parameter>, int 
<parameter>nargs</parameter>,
-                              Oid * <parameter>argtypes</parameter>, int 
<parameter>cursorOptions</parameter>)
+                              const Oid * <parameter>argtypes</parameter>, int 
<parameter>cursorOptions</parameter>)
 </synopsis>
  </refsynopsisdiv>
 
@@ -2316,7 +2316,7 @@ <title>Return Value</title>
 <synopsis>
 Portal SPI_cursor_open_with_args(const char *<parameter>name</parameter>,
                                  const char *<parameter>command</parameter>,
-                                 int <parameter>nargs</parameter>, Oid 
*<parameter>argtypes</parameter>,
+                                 int <parameter>nargs</parameter>, const Oid 
*<parameter>argtypes</parameter>,
                                  const Datum *<parameter>values</parameter>, 
const char *<parameter>nulls</parameter>,
                                  bool <parameter>read_only</parameter>, int 
<parameter>cursorOptions</parameter>)
 </synopsis>
diff --git a/src/backend/executor/spi.c b/src/backend/executor/spi.c
index 52f3b11301c..d884c962f14 100644
--- a/src/backend/executor/spi.c
+++ b/src/backend/executor/spi.c
@@ -68,7 +68,7 @@ static int    _SPI_execute_plan(SPIPlanPtr plan, const 
SPIExecuteOptions *options,
                                                          Snapshot snapshot, 
Snapshot crosscheck_snapshot,
                                                          bool fire_triggers);
 
-static ParamListInfo _SPI_convert_params(int nargs, Oid *argtypes,
+static ParamListInfo _SPI_convert_params(int nargs, const Oid *argtypes,
                                                                                
 const Datum *Values, const char *Nulls);
 
 static int     _SPI_pquery(QueryDesc *queryDesc, bool fire_triggers, uint64 
tcount);
@@ -811,7 +811,7 @@ SPI_execute_snapshot(SPIPlanPtr plan,
  */
 int
 SPI_execute_with_args(const char *src,
-                                         int nargs, Oid *argtypes,
+                                         int nargs, const Oid *argtypes,
                                          const Datum *Values, const char 
*Nulls,
                                          bool read_only, long tcount)
 {
@@ -858,13 +858,13 @@ SPI_execute_with_args(const char *src,
 }
 
 SPIPlanPtr
-SPI_prepare(const char *src, int nargs, Oid *argtypes)
+SPI_prepare(const char *src, int nargs, const Oid *argtypes)
 {
        return SPI_prepare_cursor(src, nargs, argtypes, 0);
 }
 
 SPIPlanPtr
-SPI_prepare_cursor(const char *src, int nargs, Oid *argtypes,
+SPI_prepare_cursor(const char *src, int nargs, const Oid *argtypes,
                                   int cursorOptions)
 {
        _SPI_plan       plan;
@@ -1472,7 +1472,7 @@ SPI_cursor_open(const char *name, SPIPlanPtr plan,
 Portal
 SPI_cursor_open_with_args(const char *name,
                                                  const char *src,
-                                                 int nargs, Oid *argtypes,
+                                                 int nargs, const Oid 
*argtypes,
                                                  Datum *Values, const char 
*Nulls,
                                                  bool read_only, int 
cursorOptions)
 {
@@ -2846,7 +2846,7 @@ _SPI_execute_plan(SPIPlanPtr plan, const 
SPIExecuteOptions *options,
  * Convert arrays of query parameters to form wanted by planner and executor
  */
 static ParamListInfo
-_SPI_convert_params(int nargs, Oid *argtypes,
+_SPI_convert_params(int nargs, const Oid *argtypes,
                                        const Datum *Values, const char *Nulls)
 {
        ParamListInfo paramLI;
@@ -3170,8 +3170,11 @@ _SPI_make_plan_non_temp(SPIPlanPtr plan)
        newplan->nargs = plan->nargs;
        if (plan->nargs > 0)
        {
-               newplan->argtypes = palloc_array(Oid, plan->nargs);
-               memcpy(newplan->argtypes, plan->argtypes, plan->nargs * 
sizeof(Oid));
+               Oid                *newplan_argtypes;
+
+               newplan_argtypes = palloc_array(Oid, plan->nargs);
+               memcpy(newplan_argtypes, plan->argtypes, plan->nargs * 
sizeof(Oid));
+               newplan->argtypes = newplan_argtypes;
        }
        else
                newplan->argtypes = NULL;
@@ -3235,8 +3238,11 @@ _SPI_save_plan(SPIPlanPtr plan)
        newplan->nargs = plan->nargs;
        if (plan->nargs > 0)
        {
-               newplan->argtypes = palloc_array(Oid, plan->nargs);
-               memcpy(newplan->argtypes, plan->argtypes, plan->nargs * 
sizeof(Oid));
+               Oid                *newplan_argtypes;
+
+               newplan_argtypes = palloc_array(Oid, plan->nargs);
+               memcpy(newplan_argtypes, plan->argtypes, plan->nargs * 
sizeof(Oid));
+               newplan->argtypes = newplan_argtypes;
        }
        else
                newplan->argtypes = NULL;
diff --git a/src/backend/utils/adt/ri_triggers.c 
b/src/backend/utils/adt/ri_triggers.c
index dc89c686394..4741b559c61 100644
--- a/src/backend/utils/adt/ri_triggers.c
+++ b/src/backend/utils/adt/ri_triggers.c
@@ -301,7 +301,7 @@ static RI_ConstraintInfo *ri_FetchConstraintInfo(Trigger 
*trigger,
                                                                                
                 Relation trig_rel, bool rel_is_pk);
 static RI_ConstraintInfo *ri_LoadConstraintInfo(Oid constraintOid);
 static Oid     get_ri_constraint_root(Oid constrOid);
-static SPIPlanPtr ri_PlanCheck(const char *querystr, int nargs, Oid *argtypes,
+static SPIPlanPtr ri_PlanCheck(const char *querystr, int nargs, const Oid 
*argtypes,
                                                           RI_QueryKey *qkey, 
Relation fk_rel, Relation pk_rel);
 static bool ri_PerformCheck(const RI_ConstraintInfo *riinfo,
                                                        RI_QueryKey *qkey, 
SPIPlanPtr qplan,
@@ -2582,7 +2582,7 @@ InvalidateConstraintCacheCallBack(Datum arg, 
SysCacheIdentifier cacheid,
  * Prepare execution plan for a query to enforce an RI restriction
  */
 static SPIPlanPtr
-ri_PlanCheck(const char *querystr, int nargs, Oid *argtypes,
+ri_PlanCheck(const char *querystr, int nargs, const Oid *argtypes,
                         RI_QueryKey *qkey, Relation fk_rel, Relation pk_rel)
 {
        SPIPlanPtr      qplan;
diff --git a/src/backend/utils/cache/plancache.c 
b/src/backend/utils/cache/plancache.c
index 698e7c1aa22..26f1bd64515 100644
--- a/src/backend/utils/cache/plancache.c
+++ b/src/backend/utils/cache/plancache.c
@@ -393,7 +393,7 @@ void
 CompleteCachedPlan(CachedPlanSource *plansource,
                                   List *querytree_list,
                                   MemoryContext querytree_context,
-                                  Oid *param_types,
+                                  const Oid *param_types,
                                   int num_params,
                                   ParserSetupHook parserSetup,
                                   void *parserSetupArg,
diff --git a/src/include/executor/spi.h b/src/include/executor/spi.h
index f4985cb715d..e809ba18098 100644
--- a/src/include/executor/spi.h
+++ b/src/include/executor/spi.h
@@ -127,11 +127,11 @@ extern int        SPI_execute_snapshot(SPIPlanPtr plan,
                                                                 Snapshot 
crosscheck_snapshot,
                                                                 bool 
read_only, bool fire_triggers, long tcount);
 extern int     SPI_execute_with_args(const char *src,
-                                                                 int nargs, 
Oid *argtypes,
+                                                                 int nargs, 
const Oid *argtypes,
                                                                  const Datum 
*Values, const char *Nulls,
                                                                  bool 
read_only, long tcount);
-extern SPIPlanPtr SPI_prepare(const char *src, int nargs, Oid *argtypes);
-extern SPIPlanPtr SPI_prepare_cursor(const char *src, int nargs, Oid *argtypes,
+extern SPIPlanPtr SPI_prepare(const char *src, int nargs, const Oid *argtypes);
+extern SPIPlanPtr SPI_prepare_cursor(const char *src, int nargs, const Oid 
*argtypes,
                                                                         int 
cursorOptions);
 extern SPIPlanPtr SPI_prepare_extended(const char *src,
                                                                           
const SPIPrepareOptions *options);
@@ -175,7 +175,7 @@ extern Portal SPI_cursor_open(const char *name, SPIPlanPtr 
plan,
                                                          const Datum *Values, 
const char *Nulls, bool read_only);
 extern Portal SPI_cursor_open_with_args(const char *name,
                                                                                
const char *src,
-                                                                               
int nargs, Oid *argtypes,
+                                                                               
int nargs, const Oid *argtypes,
                                                                                
Datum *Values, const char *Nulls,
                                                                                
bool read_only, int cursorOptions);
 extern Portal SPI_cursor_open_with_paramlist(const char *name, SPIPlanPtr plan,
diff --git a/src/include/executor/spi_priv.h b/src/include/executor/spi_priv.h
index 240383b97b9..9fb82ad0984 100644
--- a/src/include/executor/spi_priv.h
+++ b/src/include/executor/spi_priv.h
@@ -97,7 +97,7 @@ typedef struct _SPI_plan
        RawParseMode parse_mode;        /* raw_parser() mode */
        int                     cursor_options; /* Cursor options used for 
planning */
        int                     nargs;                  /* number of plan 
arguments */
-       Oid                *argtypes;           /* Argument types (NULL if 
nargs is 0) */
+       const Oid  *argtypes;           /* Argument types (NULL if nargs is 0) 
*/
        ParserSetupHook parserSetup;    /* alternative parameter spec method */
        void       *parserSetupArg;
 } _SPI_plan;
diff --git a/src/include/utils/plancache.h b/src/include/utils/plancache.h
index 7a4a85c8038..a0355e79c28 100644
--- a/src/include/utils/plancache.h
+++ b/src/include/utils/plancache.h
@@ -214,7 +214,7 @@ extern CachedPlanSource *CreateOneShotCachedPlan(RawStmt 
*raw_parse_tree,
 extern void CompleteCachedPlan(CachedPlanSource *plansource,
                                                           List *querytree_list,
                                                           MemoryContext 
querytree_context,
-                                                          Oid *param_types,
+                                                          const Oid 
*param_types,
                                                           int num_params,
                                                           ParserSetupHook 
parserSetup,
                                                           void *parserSetupArg,
-- 
2.54.0

From 31e8ae35ba8b1b7928c5e32f6f0b68459b912add Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <[email protected]>
Date: Thu, 11 Jun 2026 20:22:42 +0200
Subject: [PATCH v2 2/2] Add some more const qualifiers to SPI functions

Most SPI functions had the values/nulls pairs with const, except for
SPI_modifytuple() and SPI_cursor_open_with_args(), which only had it
for nulls.  Fix that.  In the latter case, the documentation was even
ahead of reality, so only the documentation of the former is touched
by this patch.
---
 doc/src/sgml/spi.sgml      | 2 +-
 src/backend/executor/spi.c | 6 +++---
 src/include/executor/spi.h | 4 ++--
 3 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/doc/src/sgml/spi.sgml b/doc/src/sgml/spi.sgml
index 043c6f00039..baee7bb5c0f 100644
--- a/doc/src/sgml/spi.sgml
+++ b/doc/src/sgml/spi.sgml
@@ -4694,7 +4694,7 @@ <title>Return Value</title>
  <refsynopsisdiv>
 <synopsis>
 HeapTuple SPI_modifytuple(Relation <parameter>rel</parameter>, HeapTuple 
<parameter>row</parameter>, int <parameter>ncols</parameter>,
-                          int * <parameter>colnum</parameter>, Datum * 
<parameter>values</parameter>, const char * <parameter>nulls</parameter>)
+                          const int * <parameter>colnum</parameter>, const 
Datum * <parameter>values</parameter>, const char * 
<parameter>nulls</parameter>)
 </synopsis>
  </refsynopsisdiv>
 
diff --git a/src/backend/executor/spi.c b/src/backend/executor/spi.c
index d884c962f14..6aea69295e0 100644
--- a/src/backend/executor/spi.c
+++ b/src/backend/executor/spi.c
@@ -1104,8 +1104,8 @@ SPI_returntuple(HeapTuple tuple, TupleDesc tupdesc)
 }
 
 HeapTuple
-SPI_modifytuple(Relation rel, HeapTuple tuple, int natts, int *attnum,
-                               Datum *Values, const char *Nulls)
+SPI_modifytuple(Relation rel, HeapTuple tuple, int natts, const int *attnum,
+                               const Datum *Values, const char *Nulls)
 {
        MemoryContext oldcxt;
        HeapTuple       mtuple;
@@ -1473,7 +1473,7 @@ Portal
 SPI_cursor_open_with_args(const char *name,
                                                  const char *src,
                                                  int nargs, const Oid 
*argtypes,
-                                                 Datum *Values, const char 
*Nulls,
+                                                 const Datum *Values, const 
char *Nulls,
                                                  bool read_only, int 
cursorOptions)
 {
        Portal          result;
diff --git a/src/include/executor/spi.h b/src/include/executor/spi.h
index e809ba18098..61bcf48b6bf 100644
--- a/src/include/executor/spi.h
+++ b/src/include/executor/spi.h
@@ -155,7 +155,7 @@ extern CachedPlan *SPI_plan_get_cached_plan(SPIPlanPtr 
plan);
 extern HeapTuple SPI_copytuple(HeapTuple tuple);
 extern HeapTupleHeader SPI_returntuple(HeapTuple tuple, TupleDesc tupdesc);
 extern HeapTuple SPI_modifytuple(Relation rel, HeapTuple tuple, int natts,
-                                                                int *attnum, 
Datum *Values, const char *Nulls);
+                                                                const int 
*attnum, const Datum *Values, const char *Nulls);
 extern int     SPI_fnumber(TupleDesc tupdesc, const char *fname);
 extern char *SPI_fname(TupleDesc tupdesc, int fnumber);
 extern char *SPI_getvalue(HeapTuple tuple, TupleDesc tupdesc, int fnumber);
@@ -176,7 +176,7 @@ extern Portal SPI_cursor_open(const char *name, SPIPlanPtr 
plan,
 extern Portal SPI_cursor_open_with_args(const char *name,
                                                                                
const char *src,
                                                                                
int nargs, const Oid *argtypes,
-                                                                               
Datum *Values, const char *Nulls,
+                                                                               
const Datum *Values, const char *Nulls,
                                                                                
bool read_only, int cursorOptions);
 extern Portal SPI_cursor_open_with_paramlist(const char *name, SPIPlanPtr plan,
                                                                                
         ParamListInfo params, bool read_only);
-- 
2.54.0

Reply via email to