From: Nathan Bossart <nathandbossart@gmail.com>
To: Jacob Champion <jacob.champion@enterprisedb.com>
Cc: pgsql-hackers@postgresql.org
Subject: Re: future of PQfn()
Date: Wed, 3 Jun 2026 16:36:34 -0500
Message-ID: <aiCeYhW4Ksu-BFqC@nathan> (raw)
In-Reply-To: <CAOYmi+=sO6dR6P2c48f6ZT9aOgzVdf+pjn3TMsehTPr8-Yxjsw@mail.gmail.com>
References: <ahXE28klgxIJXBLq@nathan>
<CAOYmi+m3bKWfHhAj3iKBa3mKj=_4MO3xY2WpBsB4Hx7yyAE7rw@mail.gmail.com>
<ahX6nb1aqh51IhHC@nathan>
<CAOYmi+n6eFXs_pncObs9Vhe7S1gbvepRncYJaaO98anxL8WODg@mail.gmail.com>
<ahmtVYcf4EYwz02U@nathan>
<CAOYmi+mA4Cdb+RWV2M83FbsSN85t2iuoXejA-PKNrQ_ayHOQWw@mail.gmail.com>
<ahm6kuL3L3wSYo6d@nathan>
<CAOYmi+nhtqGZAgtLvR2OdNZ8mfdY79qseEtKXnbs1jvtLNOrZA@mail.gmail.com>
<ahnB8zuR0AYegcJI@nathan>
<CAOYmi+=sO6dR6P2c48f6ZT9aOgzVdf+pjn3TMsehTPr8-Yxjsw@mail.gmail.com>
While the prepared statement deallocation idea bakes in the other thread, I
thought I'd post a new patch set here. I've reordered things a bit and
left out the conversion to prepared statements for now (although I do have
a patch for that). 0001 removes PQfn() and changes all internal uses to
PQnfn(). 0002 and 0003 are just some additional cleanup that I noticed
as I've been working on this stuff.
--
nathan
From 3d3a983333daa9e2d59887a5fdd7b8806d33c588 Mon Sep 17 00:00:00 2001
From: Nathan Bossart <nathan@postgresql.org>
Date: Mon, 1 Jun 2026 16:55:00 -0500
Subject: [PATCH v3 1/3] remove PQfn
---
doc/src/sgml/libpq.sgml | 117 +--------------------------------
src/backend/tcop/fastpath.c | 4 +-
src/include/tcop/dest.h | 4 +-
src/interfaces/libpq/fe-exec.c | 42 ++++++++++--
src/interfaces/libpq/fe-lobj.c | 38 +++++------
5 files changed, 60 insertions(+), 145 deletions(-)
diff --git a/doc/src/sgml/libpq.sgml b/doc/src/sgml/libpq.sgmlindex 7d3c3bb66d8..123e7f03902 100644--- a/doc/src/sgml/libpq.sgml+++ b/doc/src/sgml/libpq.sgml@@ -5887,7 +5887,7 @@ int PQflush(PGconn *conn);
are permitted, command strings containing multiple SQL commands are
disallowed, and so is <literal>COPY</literal>.
Using synchronous command execution functions
- such as <function>PQfn</function>,+ such as
<function>PQexec</function>,
<function>PQexecParams</function>,
<function>PQprepare</function>,
@@ -7046,121 +7046,6 @@ int PQrequestCancel(PGconn *conn);
</sect2>
</sect1>
- <sect1 id="libpq-fastpath">- <title>The Fast-Path Interface</title>-- <indexterm zone="libpq-fastpath">- <primary>fast path</primary>- </indexterm>-- <para>- <productname>PostgreSQL</productname> provides a fast-path interface- to send simple function calls to the server.- </para>-- <warning>- <para>- This interface is unsafe and should not be used. When- <parameter>result_is_int</parameter> is set to <literal>0</literal>,- <function>PQfn</function> may write data beyond the end of- <parameter>result_buf</parameter>, regardless of whether the buffer has- enough space for the requested number of bytes. Furthermore, it is- obsolete, as one can achieve similar- performance and greater functionality by setting up a prepared- statement to define the function call. Then, executing the statement- with binary transmission of parameters and results substitutes for a- fast-path function call.- </para>- </warning>-- <para>- The function <function id="libpq-PQfn">PQfn</function><indexterm><primary>PQfn</primary></indexterm>- requests execution of a server function via the fast-path interface:-<synopsis>-PGresult *PQfn(PGconn *conn,- int fnid,- int *result_buf,- int *result_len,- int result_is_int,- const PQArgBlock *args,- int nargs);--typedef struct-{- int len;- int isint;- union- {- int *ptr;- int integer;- } u;-} PQArgBlock;-</synopsis>- </para>-- <para>- The <parameter>fnid</parameter> argument is the OID of the function to be- executed. <parameter>args</parameter> and <parameter>nargs</parameter> define the- parameters to be passed to the function; they must match the declared- function argument list. When the <parameter>isint</parameter> field of a- parameter structure is true, the <parameter>u.integer</parameter> value is sent- to the server as an integer of the indicated length (this must be- 2 or 4 bytes); proper byte-swapping occurs. When <parameter>isint</parameter>- is false, the indicated number of bytes at <parameter>*u.ptr</parameter> are- sent with no processing; the data must be in the format expected by- the server for binary transmission of the function's argument data- type. (The declaration of <parameter>u.ptr</parameter> as being of- type <type>int *</type> is historical; it would be better to consider- it <type>void *</type>.)- <parameter>result_buf</parameter> points to the buffer in which to place- the function's return value. The caller must have allocated sufficient- space to store the return value. (There is no check!) The actual result- length in bytes will be returned in the integer pointed to by- <parameter>result_len</parameter>. If a 2- or 4-byte integer result- is expected, set <parameter>result_is_int</parameter> to 1, otherwise- set it to 0. Setting <parameter>result_is_int</parameter> to 1 causes- <application>libpq</application> to byte-swap the value if necessary, so that it- is delivered as a proper <type>int</type> value for the client machine;- note that a 4-byte integer is delivered into <parameter>*result_buf</parameter>- for either allowed result size.- When <parameter>result_is_int</parameter> is 0, the binary-format byte string- sent by the server is returned unmodified. (In this case it's better- to consider <parameter>result_buf</parameter> as being of- type <type>void *</type>.)- </para>-- <para>- <function>PQfn</function> always returns a valid- <structname>PGresult</structname> pointer, with- status <literal>PGRES_COMMAND_OK</literal> for success- or <literal>PGRES_FATAL_ERROR</literal> if some problem was encountered.- The result status should be- checked before the result is used. The caller is responsible for- freeing the <structname>PGresult</structname> with- <xref linkend="libpq-PQclear"/> when it is no longer needed.- </para>-- <para>- To pass a NULL argument to the function, set- the <parameter>len</parameter> field of that parameter structure- to <literal>-1</literal>; the <parameter>isint</parameter>- and <parameter>u</parameter> fields are then irrelevant.- </para>-- <para>- If the function returns NULL, <parameter>*result_len</parameter> is set- to <literal>-1</literal>, and <parameter>*result_buf</parameter> is not- modified.- </para>-- <para>- Note that it is not possible to handle set-valued results when using- this interface. Also, the function must be a plain function, not an- aggregate, window function, or procedure.- </para>-- </sect1>-
<sect1 id="libpq-notify">
<title>Asynchronous Notification</title>
diff --git a/src/backend/tcop/fastpath.c b/src/backend/tcop/fastpath.cindex 52772bc90a8..5379e4ad9f5 100644--- a/src/backend/tcop/fastpath.c+++ b/src/backend/tcop/fastpath.c@@ -11,7 +11,9 @@
* src/backend/tcop/fastpath.c
*
* NOTES
- * This cruft is the server side of PQfn.+ * This cruft is the server side of PQfn. libpq's PQfn() was retired in+ * v20 and now always errors, but the server code is retained for the+ * benefit of older clients.
*
*-------------------------------------------------------------------------
*/
diff --git a/src/include/tcop/dest.h b/src/include/tcop/dest.hindex 103f27fc3cb..507414421ec 100644--- a/src/include/tcop/dest.h+++ b/src/include/tcop/dest.h@@ -12,8 +12,8 @@
*
* - a remote process is the destination when we are
* running a backend with a frontend and the frontend executes
- * PQexec() or PQfn(). In this case, the results are sent- * to the frontend via the functions in backend/libpq.+ * PQexec(). In this case, the results are sent to the frontend via+ * the functions in backend/libpq.
*
* - DestNone is the destination when the system executes
* a query internally. The results are discarded.
diff --git a/src/interfaces/libpq/fe-exec.c b/src/interfaces/libpq/fe-exec.cindex 7b8edacbfde..2f034d70e65 100644--- a/src/interfaces/libpq/fe-exec.c+++ b/src/interfaces/libpq/fe-exec.c@@ -2986,10 +2986,10 @@ PQendcopy(PGconn *conn)
* nargs : # of arguments in args array.
*
* RETURNS
- * PGresult with status = PGRES_COMMAND_OK if successful.- * *result_len is > 0 if there is a return value, 0 if not.- * PGresult with status = PGRES_FATAL_ERROR if backend returns an error.- * NULL on communications failure. conn->errorMessage will be set.+ * This function was unsafe and is no longer supported, so it now always+ * sets *result_len to 0 and returns a PGresult with status set to+ * PGRES_FATAL_ERROR (unless the connection is in the wrong state, in+ * which case it returns NULL).
* ----------------
*/
@@ -3002,15 +3002,43 @@ PQfn(PGconn *conn,
const PQArgBlock *args,
int nargs)
{
- return PQnfn(conn, fnid, result_buf, -1, result_len,- result_is_int, args, nargs);+ *result_len = 0;++ if (!conn)+ return NULL;++ /*+ * Since this is the beginning of a query cycle, reset the error state.+ * However, in pipeline mode with something already queued, the error+ * buffer belongs to that command and we shouldn't clear it.+ */+ if (conn->cmd_queue_head == NULL)+ pqClearConnErrorState(conn);++ if (conn->pipelineStatus != PQ_PIPELINE_OFF)+ {+ libpq_append_conn_error(conn, "%s not allowed in pipeline mode", "PQfn");+ return NULL;+ }++ if (conn->sock == PGINVALID_SOCKET || conn->asyncStatus != PGASYNC_IDLE ||+ pgHavePendingResult(conn))+ {+ libpq_append_conn_error(conn, "connection in wrong state");+ return NULL;+ }++ libpq_append_conn_error(conn, "PQfn() is no longer supported; use a prepared statement or PQexecParams() with binary results instead");+ pqSaveErrorResult(conn);+ return pqPrepareAsyncResult(conn);
}
/*
* PQnfn
* Private version of PQfn() with verification that returned data fits in
* result_buf when result_is_int == 0. Setting buf_size to -1 disables
- * this verification.+ * this verification. This is currently only used by the frontend LO+ * interface and will hopefully be removed down the road.
*/
PGresult *
PQnfn(PGconn *conn, int fnid, int *result_buf, int buf_size, int *result_len,
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.cindex 12a32fcbaf3..1660c969f58 100644--- a/src/interfaces/libpq/fe-lobj.c+++ b/src/interfaces/libpq/fe-lobj.c@@ -72,7 +72,7 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
argv[1].len = 4;
argv[1].u.integer = mode;
- res = PQfn(conn, conn->lobjfuncs->fn_lo_open, &fd, &result_len, 1, argv, 2);+ res = PQnfn(conn, conn->lobjfuncs->fn_lo_open, &fd, -1, &result_len, 1, argv, 2);
if (PQresultStatus(res) == PGRES_COMMAND_OK)
{
PQclear(res);
@@ -106,8 +106,8 @@ lo_close(PGconn *conn, int fd)
argv[0].isint = 1;
argv[0].len = 4;
argv[0].u.integer = fd;
- res = PQfn(conn, conn->lobjfuncs->fn_lo_close,- &retval, &result_len, 1, argv, 1);+ res = PQnfn(conn, conn->lobjfuncs->fn_lo_close,+ &retval, -1, &result_len, 1, argv, 1);
if (PQresultStatus(res) == PGRES_COMMAND_OK)
{
PQclear(res);
@@ -169,8 +169,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
argv[1].len = 4;
argv[1].u.integer = (int) len;
- res = PQfn(conn, conn->lobjfuncs->fn_lo_truncate,- &retval, &result_len, 1, argv, 2);+ res = PQnfn(conn, conn->lobjfuncs->fn_lo_truncate,+ &retval, -1, &result_len, 1, argv, 2);
if (PQresultStatus(res) == PGRES_COMMAND_OK)
{
@@ -218,8 +218,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
argv[1].len = 8;
argv[1].u.ptr = (int *) &len;
- res = PQfn(conn, conn->lobjfuncs->fn_lo_truncate64,- &retval, &result_len, 1, argv, 2);+ res = PQnfn(conn, conn->lobjfuncs->fn_lo_truncate64,+ &retval, -1, &result_len, 1, argv, 2);
if (PQresultStatus(res) == PGRES_COMMAND_OK)
{
@@ -322,8 +322,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
argv[1].len = (int) len;
argv[1].u.ptr = (int *) unconstify(char *, buf);
- res = PQfn(conn, conn->lobjfuncs->fn_lo_write,- &retval, &result_len, 1, argv, 2);+ res = PQnfn(conn, conn->lobjfuncs->fn_lo_write,+ &retval, -1, &result_len, 1, argv, 2);
if (PQresultStatus(res) == PGRES_COMMAND_OK)
{
PQclear(res);
@@ -363,8 +363,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
argv[2].len = 4;
argv[2].u.integer = whence;
- res = PQfn(conn, conn->lobjfuncs->fn_lo_lseek,- &retval, &result_len, 1, argv, 3);+ res = PQnfn(conn, conn->lobjfuncs->fn_lo_lseek,+ &retval, -1, &result_len, 1, argv, 3);
if (PQresultStatus(res) == PGRES_COMMAND_OK)
{
PQclear(res);
@@ -448,8 +448,8 @@ lo_creat(PGconn *conn, int mode)
argv[0].isint = 1;
argv[0].len = 4;
argv[0].u.integer = mode;
- res = PQfn(conn, conn->lobjfuncs->fn_lo_creat,- &retval, &result_len, 1, argv, 1);+ res = PQnfn(conn, conn->lobjfuncs->fn_lo_creat,+ &retval, -1, &result_len, 1, argv, 1);
if (PQresultStatus(res) == PGRES_COMMAND_OK)
{
PQclear(res);
@@ -492,8 +492,8 @@ lo_create(PGconn *conn, Oid lobjId)
argv[0].isint = 1;
argv[0].len = 4;
argv[0].u.integer = lobjId;
- res = PQfn(conn, conn->lobjfuncs->fn_lo_create,- &retval, &result_len, 1, argv, 1);+ res = PQnfn(conn, conn->lobjfuncs->fn_lo_create,+ &retval, -1, &result_len, 1, argv, 1);
if (PQresultStatus(res) == PGRES_COMMAND_OK)
{
PQclear(res);
@@ -526,8 +526,8 @@ lo_tell(PGconn *conn, int fd)
argv[0].len = 4;
argv[0].u.integer = fd;
- res = PQfn(conn, conn->lobjfuncs->fn_lo_tell,- &retval, &result_len, 1, argv, 1);+ res = PQnfn(conn, conn->lobjfuncs->fn_lo_tell,+ &retval, -1, &result_len, 1, argv, 1);
if (PQresultStatus(res) == PGRES_COMMAND_OK)
{
PQclear(res);
@@ -600,8 +600,8 @@ lo_unlink(PGconn *conn, Oid lobjId)
argv[0].len = 4;
argv[0].u.integer = lobjId;
- res = PQfn(conn, conn->lobjfuncs->fn_lo_unlink,- &retval, &result_len, 1, argv, 1);+ res = PQnfn(conn, conn->lobjfuncs->fn_lo_unlink,+ &retval, -1, &result_len, 1, argv, 1);
if (PQresultStatus(res) == PGRES_COMMAND_OK)
{
PQclear(res);
--
2.50.1 (Apple Git-155)
From 8b03849dadebe8d6c31be83b2ab3f5c8736adb32 Mon Sep 17 00:00:00 2001
From: Reviewer <review@example.com>
Date: Tue, 2 Jun 2026 17:22:48 +0000
Subject: [PATCH v3 2/3] remove lo_hton64() and lo_ntoh64()
---
src/interfaces/libpq/fe-lobj.c | 58 +++-------------------------------
1 file changed, 4 insertions(+), 54 deletions(-)
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.cindex 1660c969f58..42b2a36bda9 100644--- a/src/interfaces/libpq/fe-lobj.c+++ b/src/interfaces/libpq/fe-lobj.c@@ -43,8 +43,6 @@
static int lo_initialize(PGconn *conn);
static Oid lo_import_internal(PGconn *conn, const char *filename, Oid oid);
-static int64_t lo_hton64(int64_t host64);-static int64_t lo_ntoh64(int64_t net64);
/*
* lo_open
@@ -213,7 +211,7 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
argv[0].len = 4;
argv[0].u.integer = fd;
- len = lo_hton64(len);+ len = pg_hton64(len);
argv[1].isint = 0;
argv[1].len = 8;
argv[1].u.ptr = (int *) &len;
@@ -403,7 +401,7 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
argv[0].len = 4;
argv[0].u.integer = fd;
- offset = lo_hton64(offset);+ offset = pg_hton64(offset);
argv[1].isint = 0;
argv[1].len = 8;
argv[1].u.ptr = (int *) &offset;
@@ -417,7 +415,7 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
if (PQresultStatus(res) == PGRES_COMMAND_OK && result_len == 8)
{
PQclear(res);
- return lo_ntoh64(retval);+ return pg_ntoh64(retval);
}
else
{
@@ -571,7 +569,7 @@ lo_tell64(PGconn *conn, int fd)
if (PQresultStatus(res) == PGRES_COMMAND_OK && result_len == 8)
{
PQclear(res);
- return lo_ntoh64(retval);+ return pg_ntoh64(retval);
}
else
{
@@ -1014,51 +1012,3 @@ lo_initialize(PGconn *conn)
conn->lobjfuncs = lobjfuncs;
return 0;
}
--/*- * lo_hton64- * converts a 64-bit integer from host byte order to network byte order- */-static int64_t-lo_hton64(int64_t host64)-{- union- {- int64 i64;- uint32 i32[2];- } swap;- uint32 t;-- /* High order half first, since we're doing MSB-first */- t = (uint32) (host64 >> 32);- swap.i32[0] = pg_hton32(t);-- /* Now the low order half */- t = (uint32) host64;- swap.i32[1] = pg_hton32(t);-- return swap.i64;-}--/*- * lo_ntoh64- * converts a 64-bit integer from network byte order to host byte order- */-static int64_t-lo_ntoh64(int64_t net64)-{- union- {- int64 i64;- uint32 i32[2];- } swap;- int64 result;-- swap.i64 = net64;-- result = (uint32) pg_ntoh32(swap.i32[0]);- result <<= 32;- result |= (uint32) pg_ntoh32(swap.i32[1]);-- return result;-}
--
2.50.1 (Apple Git-155)
From e5b1df7a69d0d0f1798ce0dc2beb18fedfdfd081 Mon Sep 17 00:00:00 2001
From: Reviewer <review@example.com>
Date: Tue, 2 Jun 2026 18:24:30 +0000
Subject: [PATCH v3 3/3] add helper functions for fast-path arg setup
---
src/interfaces/libpq/fe-lobj.c | 104 ++++++++++++---------------------
1 file changed, 38 insertions(+), 66 deletions(-)
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.cindex 42b2a36bda9..8802c6f8098 100644--- a/src/interfaces/libpq/fe-lobj.c+++ b/src/interfaces/libpq/fe-lobj.c@@ -44,6 +44,22 @@
static int lo_initialize(PGconn *conn);
static Oid lo_import_internal(PGconn *conn, const char *filename, Oid oid);
+static inline void+lo_set_int_arg(PQArgBlock *arg, int value)+{+ arg->isint = 1;+ arg->len = 4;+ arg->u.integer = value;+}++static inline void+lo_set_ptr_arg(PQArgBlock *arg, const void *ptr, int len)+{+ arg->isint = 0;+ arg->len = len;+ arg->u.ptr = (int *) unconstify(void *, ptr);+}+
/*
* lo_open
* opens an existing large object
@@ -62,13 +78,9 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
if (lo_initialize(conn) < 0)
return -1;
- argv[0].isint = 1;- argv[0].len = 4;- argv[0].u.integer = lobjId;+ lo_set_int_arg(&argv[0], lobjId);- argv[1].isint = 1;- argv[1].len = 4;- argv[1].u.integer = mode;+ lo_set_int_arg(&argv[1], mode);
res = PQnfn(conn, conn->lobjfuncs->fn_lo_open, &fd, -1, &result_len, 1, argv, 2);
if (PQresultStatus(res) == PGRES_COMMAND_OK)
@@ -101,9 +113,7 @@ lo_close(PGconn *conn, int fd)
if (lo_initialize(conn) < 0)
return -1;
- argv[0].isint = 1;- argv[0].len = 4;- argv[0].u.integer = fd;+ lo_set_int_arg(&argv[0], fd);
res = PQnfn(conn, conn->lobjfuncs->fn_lo_close,
&retval, -1, &result_len, 1, argv, 1);
if (PQresultStatus(res) == PGRES_COMMAND_OK)
@@ -159,13 +169,9 @@ lo_truncate(PGconn *conn, int fd, size_t len)
return -1;
}
- argv[0].isint = 1;- argv[0].len = 4;- argv[0].u.integer = fd;+ lo_set_int_arg(&argv[0], fd);- argv[1].isint = 1;- argv[1].len = 4;- argv[1].u.integer = (int) len;+ lo_set_int_arg(&argv[1], (int) len);
res = PQnfn(conn, conn->lobjfuncs->fn_lo_truncate,
&retval, -1, &result_len, 1, argv, 2);
@@ -207,14 +213,10 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
return -1;
}
- argv[0].isint = 1;- argv[0].len = 4;- argv[0].u.integer = fd;+ lo_set_int_arg(&argv[0], fd);
len = pg_hton64(len);
- argv[1].isint = 0;- argv[1].len = 8;- argv[1].u.ptr = (int *) &len;+ lo_set_ptr_arg(&argv[1], &len, 8);
res = PQnfn(conn, conn->lobjfuncs->fn_lo_truncate64,
&retval, -1, &result_len, 1, argv, 2);
@@ -261,13 +263,9 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
return -1;
}
- argv[0].isint = 1;- argv[0].len = 4;- argv[0].u.integer = fd;+ lo_set_int_arg(&argv[0], fd);- argv[1].isint = 1;- argv[1].len = 4;- argv[1].u.integer = (int) len;+ lo_set_int_arg(&argv[1], (int) len);
res = PQnfn(conn, conn->lobjfuncs->fn_lo_read,
(void *) buf, len, &result_len, 0, argv, 2);
@@ -312,13 +310,9 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
return -1;
}
- argv[0].isint = 1;- argv[0].len = 4;- argv[0].u.integer = fd;+ lo_set_int_arg(&argv[0], fd);- argv[1].isint = 0;- argv[1].len = (int) len;- argv[1].u.ptr = (int *) unconstify(char *, buf);+ lo_set_ptr_arg(&argv[1], buf, (int) len);
res = PQnfn(conn, conn->lobjfuncs->fn_lo_write,
&retval, -1, &result_len, 1, argv, 2);
@@ -349,17 +343,11 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
if (lo_initialize(conn) < 0)
return -1;
- argv[0].isint = 1;- argv[0].len = 4;- argv[0].u.integer = fd;+ lo_set_int_arg(&argv[0], fd);- argv[1].isint = 1;- argv[1].len = 4;- argv[1].u.integer = offset;+ lo_set_int_arg(&argv[1], offset);- argv[2].isint = 1;- argv[2].len = 4;- argv[2].u.integer = whence;+ lo_set_int_arg(&argv[2], whence);
res = PQnfn(conn, conn->lobjfuncs->fn_lo_lseek,
&retval, -1, &result_len, 1, argv, 3);
@@ -397,18 +385,12 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
return -1;
}
- argv[0].isint = 1;- argv[0].len = 4;- argv[0].u.integer = fd;+ lo_set_int_arg(&argv[0], fd);
offset = pg_hton64(offset);
- argv[1].isint = 0;- argv[1].len = 8;- argv[1].u.ptr = (int *) &offset;+ lo_set_ptr_arg(&argv[1], &offset, 8);- argv[2].isint = 1;- argv[2].len = 4;- argv[2].u.integer = whence;+ lo_set_int_arg(&argv[2], whence);
res = PQnfn(conn, conn->lobjfuncs->fn_lo_lseek64,
(void *) &retval, sizeof(retval), &result_len, 0, argv, 3);
@@ -443,9 +425,7 @@ lo_creat(PGconn *conn, int mode)
if (lo_initialize(conn) < 0)
return InvalidOid;
- argv[0].isint = 1;- argv[0].len = 4;- argv[0].u.integer = mode;+ lo_set_int_arg(&argv[0], mode);
res = PQnfn(conn, conn->lobjfuncs->fn_lo_creat,
&retval, -1, &result_len, 1, argv, 1);
if (PQresultStatus(res) == PGRES_COMMAND_OK)
@@ -487,9 +467,7 @@ lo_create(PGconn *conn, Oid lobjId)
return InvalidOid;
}
- argv[0].isint = 1;- argv[0].len = 4;- argv[0].u.integer = lobjId;+ lo_set_int_arg(&argv[0], lobjId);
res = PQnfn(conn, conn->lobjfuncs->fn_lo_create,
&retval, -1, &result_len, 1, argv, 1);
if (PQresultStatus(res) == PGRES_COMMAND_OK)
@@ -520,9 +498,7 @@ lo_tell(PGconn *conn, int fd)
if (lo_initialize(conn) < 0)
return -1;
- argv[0].isint = 1;- argv[0].len = 4;- argv[0].u.integer = fd;+ lo_set_int_arg(&argv[0], fd);
res = PQnfn(conn, conn->lobjfuncs->fn_lo_tell,
&retval, -1, &result_len, 1, argv, 1);
@@ -560,9 +536,7 @@ lo_tell64(PGconn *conn, int fd)
return -1;
}
- argv[0].isint = 1;- argv[0].len = 4;- argv[0].u.integer = fd;+ lo_set_int_arg(&argv[0], fd);
res = PQnfn(conn, conn->lobjfuncs->fn_lo_tell64,
(void *) &retval, sizeof(retval), &result_len, 0, argv, 1);
@@ -594,9 +568,7 @@ lo_unlink(PGconn *conn, Oid lobjId)
if (lo_initialize(conn) < 0)
return -1;
- argv[0].isint = 1;- argv[0].len = 4;- argv[0].u.integer = lobjId;+ lo_set_int_arg(&argv[0], lobjId);
res = PQnfn(conn, conn->lobjfuncs->fn_lo_unlink,
&retval, -1, &result_len, 1, argv, 1);
--
2.50.1 (Apple Git-155)
Attachments:
[text/plain] v3-0001-remove-PQfn.patch (13.1K, ../aiCeYhW4Ksu-BFqC@nathan/2-v3-0001-remove-PQfn.patch)
download | inline diff:
From 3d3a983333daa9e2d59887a5fdd7b8806d33c588 Mon Sep 17 00:00:00 2001
From: Nathan Bossart <nathan@postgresql.org>
Date: Mon, 1 Jun 2026 16:55:00 -0500
Subject: [PATCH v3 1/3] remove PQfn
---
doc/src/sgml/libpq.sgml | 117 +--------------------------------
src/backend/tcop/fastpath.c | 4 +-
src/include/tcop/dest.h | 4 +-
src/interfaces/libpq/fe-exec.c | 42 ++++++++++--
src/interfaces/libpq/fe-lobj.c | 38 +++++------
5 files changed, 60 insertions(+), 145 deletions(-)
diff --git a/doc/src/sgml/libpq.sgml b/doc/src/sgml/libpq.sgmlindex 7d3c3bb66d8..123e7f03902 100644--- a/doc/src/sgml/libpq.sgml+++ b/doc/src/sgml/libpq.sgml@@ -5887,7 +5887,7 @@ int PQflush(PGconn *conn);
are permitted, command strings containing multiple SQL commands are
disallowed, and so is <literal>COPY</literal>.
Using synchronous command execution functions
- such as <function>PQfn</function>,+ such as
<function>PQexec</function>,
<function>PQexecParams</function>,
<function>PQprepare</function>,
@@ -7046,121 +7046,6 @@ int PQrequestCancel(PGconn *conn);
</sect2>
</sect1>
- <sect1 id="libpq-fastpath">- <title>The Fast-Path Interface</title>-- <indexterm zone="libpq-fastpath">- <primary>fast path</primary>- </indexterm>-- <para>- <productname>PostgreSQL</productname> provides a fast-path interface- to send simple function calls to the server.- </para>-- <warning>- <para>- This interface is unsafe and should not be used. When- <parameter>result_is_int</parameter> is set to <literal>0</literal>,- <function>PQfn</function> may write data beyond the end of- <parameter>result_buf</parameter>, regardless of whether the buffer has- enough space for the requested number of bytes. Furthermore, it is- obsolete, as one can achieve similar- performance and greater functionality by setting up a prepared- statement to define the function call. Then, executing the statement- with binary transmission of parameters and results substitutes for a- fast-path function call.- </para>- </warning>-- <para>- The function <function id="libpq-PQfn">PQfn</function><indexterm><primary>PQfn</primary></indexterm>- requests execution of a server function via the fast-path interface:-<synopsis>-PGresult *PQfn(PGconn *conn,- int fnid,- int *result_buf,- int *result_len,- int result_is_int,- const PQArgBlock *args,- int nargs);--typedef struct-{- int len;- int isint;- union- {- int *ptr;- int integer;- } u;-} PQArgBlock;-</synopsis>- </para>-- <para>- The <parameter>fnid</parameter> argument is the OID of the function to be- executed. <parameter>args</parameter> and <parameter>nargs</parameter> define the- parameters to be passed to the function; they must match the declared- function argument list. When the <parameter>isint</parameter> field of a- parameter structure is true, the <parameter>u.integer</parameter> value is sent- to the server as an integer of the indicated length (this must be- 2 or 4 bytes); proper byte-swapping occurs. When <parameter>isint</parameter>- is false, the indicated number of bytes at <parameter>*u.ptr</parameter> are- sent with no processing; the data must be in the format expected by- the server for binary transmission of the function's argument data- type. (The declaration of <parameter>u.ptr</parameter> as being of- type <type>int *</type> is historical; it would be better to consider- it <type>void *</type>.)- <parameter>result_buf</parameter> points to the buffer in which to place- the function's return value. The caller must have allocated sufficient- space to store the return value. (There is no check!) The actual result- length in bytes will be returned in the integer pointed to by- <parameter>result_len</parameter>. If a 2- or 4-byte integer result- is expected, set <parameter>result_is_int</parameter> to 1, otherwise- set it to 0. Setting <parameter>result_is_int</parameter> to 1 causes- <application>libpq</application> to byte-swap the value if necessary, so that it- is delivered as a proper <type>int</type> value for the client machine;- note that a 4-byte integer is delivered into <parameter>*result_buf</parameter>- for either allowed result size.- When <parameter>result_is_int</parameter> is 0, the binary-format byte string- sent by the server is returned unmodified. (In this case it's better- to consider <parameter>result_buf</parameter> as being of- type <type>void *</type>.)- </para>-- <para>- <function>PQfn</function> always returns a valid- <structname>PGresult</structname> pointer, with- status <literal>PGRES_COMMAND_OK</literal> for success- or <literal>PGRES_FATAL_ERROR</literal> if some problem was encountered.- The result status should be- checked before the result is used. The caller is responsible for- freeing the <structname>PGresult</structname> with- <xref linkend="libpq-PQclear"/> when it is no longer needed.- </para>-- <para>- To pass a NULL argument to the function, set- the <parameter>len</parameter> field of that parameter structure- to <literal>-1</literal>; the <parameter>isint</parameter>- and <parameter>u</parameter> fields are then irrelevant.- </para>-- <para>- If the function returns NULL, <parameter>*result_len</parameter> is set- to <literal>-1</literal>, and <parameter>*result_buf</parameter> is not- modified.- </para>-- <para>- Note that it is not possible to handle set-valued results when using- this interface. Also, the function must be a plain function, not an- aggregate, window function, or procedure.- </para>-- </sect1>-
<sect1 id="libpq-notify">
<title>Asynchronous Notification</title>
diff --git a/src/backend/tcop/fastpath.c b/src/backend/tcop/fastpath.cindex 52772bc90a8..5379e4ad9f5 100644--- a/src/backend/tcop/fastpath.c+++ b/src/backend/tcop/fastpath.c@@ -11,7 +11,9 @@
* src/backend/tcop/fastpath.c
*
* NOTES
- * This cruft is the server side of PQfn.+ * This cruft is the server side of PQfn. libpq's PQfn() was retired in+ * v20 and now always errors, but the server code is retained for the+ * benefit of older clients.
*
*-------------------------------------------------------------------------
*/
diff --git a/src/include/tcop/dest.h b/src/include/tcop/dest.hindex 103f27fc3cb..507414421ec 100644--- a/src/include/tcop/dest.h+++ b/src/include/tcop/dest.h@@ -12,8 +12,8 @@
*
* - a remote process is the destination when we are
* running a backend with a frontend and the frontend executes
- * PQexec() or PQfn(). In this case, the results are sent- * to the frontend via the functions in backend/libpq.+ * PQexec(). In this case, the results are sent to the frontend via+ * the functions in backend/libpq.
*
* - DestNone is the destination when the system executes
* a query internally. The results are discarded.
diff --git a/src/interfaces/libpq/fe-exec.c b/src/interfaces/libpq/fe-exec.cindex 7b8edacbfde..2f034d70e65 100644--- a/src/interfaces/libpq/fe-exec.c+++ b/src/interfaces/libpq/fe-exec.c@@ -2986,10 +2986,10 @@ PQendcopy(PGconn *conn)
* nargs : # of arguments in args array.
*
* RETURNS
- * PGresult with status = PGRES_COMMAND_OK if successful.- * *result_len is > 0 if there is a return value, 0 if not.- * PGresult with status = PGRES_FATAL_ERROR if backend returns an error.- * NULL on communications failure. conn->errorMessage will be set.+ * This function was unsafe and is no longer supported, so it now always+ * sets *result_len to 0 and returns a PGresult with status set to+ * PGRES_FATAL_ERROR (unless the connection is in the wrong state, in+ * which case it returns NULL).
* ----------------
*/
@@ -3002,15 +3002,43 @@ PQfn(PGconn *conn,
const PQArgBlock *args,
int nargs)
{
- return PQnfn(conn, fnid, result_buf, -1, result_len,- result_is_int, args, nargs);+ *result_len = 0;++ if (!conn)+ return NULL;++ /*+ * Since this is the beginning of a query cycle, reset the error state.+ * However, in pipeline mode with something already queued, the error+ * buffer belongs to that command and we shouldn't clear it.+ */+ if (conn->cmd_queue_head == NULL)+ pqClearConnErrorState(conn);++ if (conn->pipelineStatus != PQ_PIPELINE_OFF)+ {+ libpq_append_conn_error(conn, "%s not allowed in pipeline mode", "PQfn");+ return NULL;+ }++ if (conn->sock == PGINVALID_SOCKET || conn->asyncStatus != PGASYNC_IDLE ||+ pgHavePendingResult(conn))+ {+ libpq_append_conn_error(conn, "connection in wrong state");+ return NULL;+ }++ libpq_append_conn_error(conn, "PQfn() is no longer supported; use a prepared statement or PQexecParams() with binary results instead");+ pqSaveErrorResult(conn);+ return pqPrepareAsyncResult(conn);
}
/*
* PQnfn
* Private version of PQfn() with verification that returned data fits in
* result_buf when result_is_int == 0. Setting buf_size to -1 disables
- * this verification.+ * this verification. This is currently only used by the frontend LO+ * interface and will hopefully be removed down the road.
*/
PGresult *
PQnfn(PGconn *conn, int fnid, int *result_buf, int buf_size, int *result_len,
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.cindex 12a32fcbaf3..1660c969f58 100644--- a/src/interfaces/libpq/fe-lobj.c+++ b/src/interfaces/libpq/fe-lobj.c@@ -72,7 +72,7 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
argv[1].len = 4;
argv[1].u.integer = mode;
- res = PQfn(conn, conn->lobjfuncs->fn_lo_open, &fd, &result_len, 1, argv, 2);+ res = PQnfn(conn, conn->lobjfuncs->fn_lo_open, &fd, -1, &result_len, 1, argv, 2);
if (PQresultStatus(res) == PGRES_COMMAND_OK)
{
PQclear(res);
@@ -106,8 +106,8 @@ lo_close(PGconn *conn, int fd)
argv[0].isint = 1;
argv[0].len = 4;
argv[0].u.integer = fd;
- res = PQfn(conn, conn->lobjfuncs->fn_lo_close,- &retval, &result_len, 1, argv, 1);+ res = PQnfn(conn, conn->lobjfuncs->fn_lo_close,+ &retval, -1, &result_len, 1, argv, 1);
if (PQresultStatus(res) == PGRES_COMMAND_OK)
{
PQclear(res);
@@ -169,8 +169,8 @@ lo_truncate(PGconn *conn, int fd, size_t len)
argv[1].len = 4;
argv[1].u.integer = (int) len;
- res = PQfn(conn, conn->lobjfuncs->fn_lo_truncate,- &retval, &result_len, 1, argv, 2);+ res = PQnfn(conn, conn->lobjfuncs->fn_lo_truncate,+ &retval, -1, &result_len, 1, argv, 2);
if (PQresultStatus(res) == PGRES_COMMAND_OK)
{
@@ -218,8 +218,8 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
argv[1].len = 8;
argv[1].u.ptr = (int *) &len;
- res = PQfn(conn, conn->lobjfuncs->fn_lo_truncate64,- &retval, &result_len, 1, argv, 2);+ res = PQnfn(conn, conn->lobjfuncs->fn_lo_truncate64,+ &retval, -1, &result_len, 1, argv, 2);
if (PQresultStatus(res) == PGRES_COMMAND_OK)
{
@@ -322,8 +322,8 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
argv[1].len = (int) len;
argv[1].u.ptr = (int *) unconstify(char *, buf);
- res = PQfn(conn, conn->lobjfuncs->fn_lo_write,- &retval, &result_len, 1, argv, 2);+ res = PQnfn(conn, conn->lobjfuncs->fn_lo_write,+ &retval, -1, &result_len, 1, argv, 2);
if (PQresultStatus(res) == PGRES_COMMAND_OK)
{
PQclear(res);
@@ -363,8 +363,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
argv[2].len = 4;
argv[2].u.integer = whence;
- res = PQfn(conn, conn->lobjfuncs->fn_lo_lseek,- &retval, &result_len, 1, argv, 3);+ res = PQnfn(conn, conn->lobjfuncs->fn_lo_lseek,+ &retval, -1, &result_len, 1, argv, 3);
if (PQresultStatus(res) == PGRES_COMMAND_OK)
{
PQclear(res);
@@ -448,8 +448,8 @@ lo_creat(PGconn *conn, int mode)
argv[0].isint = 1;
argv[0].len = 4;
argv[0].u.integer = mode;
- res = PQfn(conn, conn->lobjfuncs->fn_lo_creat,- &retval, &result_len, 1, argv, 1);+ res = PQnfn(conn, conn->lobjfuncs->fn_lo_creat,+ &retval, -1, &result_len, 1, argv, 1);
if (PQresultStatus(res) == PGRES_COMMAND_OK)
{
PQclear(res);
@@ -492,8 +492,8 @@ lo_create(PGconn *conn, Oid lobjId)
argv[0].isint = 1;
argv[0].len = 4;
argv[0].u.integer = lobjId;
- res = PQfn(conn, conn->lobjfuncs->fn_lo_create,- &retval, &result_len, 1, argv, 1);+ res = PQnfn(conn, conn->lobjfuncs->fn_lo_create,+ &retval, -1, &result_len, 1, argv, 1);
if (PQresultStatus(res) == PGRES_COMMAND_OK)
{
PQclear(res);
@@ -526,8 +526,8 @@ lo_tell(PGconn *conn, int fd)
argv[0].len = 4;
argv[0].u.integer = fd;
- res = PQfn(conn, conn->lobjfuncs->fn_lo_tell,- &retval, &result_len, 1, argv, 1);+ res = PQnfn(conn, conn->lobjfuncs->fn_lo_tell,+ &retval, -1, &result_len, 1, argv, 1);
if (PQresultStatus(res) == PGRES_COMMAND_OK)
{
PQclear(res);
@@ -600,8 +600,8 @@ lo_unlink(PGconn *conn, Oid lobjId)
argv[0].len = 4;
argv[0].u.integer = lobjId;
- res = PQfn(conn, conn->lobjfuncs->fn_lo_unlink,- &retval, &result_len, 1, argv, 1);+ res = PQnfn(conn, conn->lobjfuncs->fn_lo_unlink,+ &retval, -1, &result_len, 1, argv, 1);
if (PQresultStatus(res) == PGRES_COMMAND_OK)
{
PQclear(res);
--
2.50.1 (Apple Git-155)
[text/plain] v3-0002-remove-lo_hton64-and-lo_ntoh64.patch (2.6K, ../aiCeYhW4Ksu-BFqC@nathan/3-v3-0002-remove-lo_hton64-and-lo_ntoh64.patch)
download | inline diff:
From 8b03849dadebe8d6c31be83b2ab3f5c8736adb32 Mon Sep 17 00:00:00 2001
From: Reviewer <review@example.com>
Date: Tue, 2 Jun 2026 17:22:48 +0000
Subject: [PATCH v3 2/3] remove lo_hton64() and lo_ntoh64()
---
src/interfaces/libpq/fe-lobj.c | 58 +++-------------------------------
1 file changed, 4 insertions(+), 54 deletions(-)
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.cindex 1660c969f58..42b2a36bda9 100644--- a/src/interfaces/libpq/fe-lobj.c+++ b/src/interfaces/libpq/fe-lobj.c@@ -43,8 +43,6 @@
static int lo_initialize(PGconn *conn);
static Oid lo_import_internal(PGconn *conn, const char *filename, Oid oid);
-static int64_t lo_hton64(int64_t host64);-static int64_t lo_ntoh64(int64_t net64);
/*
* lo_open
@@ -213,7 +211,7 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
argv[0].len = 4;
argv[0].u.integer = fd;
- len = lo_hton64(len);+ len = pg_hton64(len);
argv[1].isint = 0;
argv[1].len = 8;
argv[1].u.ptr = (int *) &len;
@@ -403,7 +401,7 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
argv[0].len = 4;
argv[0].u.integer = fd;
- offset = lo_hton64(offset);+ offset = pg_hton64(offset);
argv[1].isint = 0;
argv[1].len = 8;
argv[1].u.ptr = (int *) &offset;
@@ -417,7 +415,7 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
if (PQresultStatus(res) == PGRES_COMMAND_OK && result_len == 8)
{
PQclear(res);
- return lo_ntoh64(retval);+ return pg_ntoh64(retval);
}
else
{
@@ -571,7 +569,7 @@ lo_tell64(PGconn *conn, int fd)
if (PQresultStatus(res) == PGRES_COMMAND_OK && result_len == 8)
{
PQclear(res);
- return lo_ntoh64(retval);+ return pg_ntoh64(retval);
}
else
{
@@ -1014,51 +1012,3 @@ lo_initialize(PGconn *conn)
conn->lobjfuncs = lobjfuncs;
return 0;
}
--/*- * lo_hton64- * converts a 64-bit integer from host byte order to network byte order- */-static int64_t-lo_hton64(int64_t host64)-{- union- {- int64 i64;- uint32 i32[2];- } swap;- uint32 t;-- /* High order half first, since we're doing MSB-first */- t = (uint32) (host64 >> 32);- swap.i32[0] = pg_hton32(t);-- /* Now the low order half */- t = (uint32) host64;- swap.i32[1] = pg_hton32(t);-- return swap.i64;-}--/*- * lo_ntoh64- * converts a 64-bit integer from network byte order to host byte order- */-static int64_t-lo_ntoh64(int64_t net64)-{- union- {- int64 i64;- uint32 i32[2];- } swap;- int64 result;-- swap.i64 = net64;-- result = (uint32) pg_ntoh32(swap.i32[0]);- result <<= 32;- result |= (uint32) pg_ntoh32(swap.i32[1]);-- return result;-}--
2.50.1 (Apple Git-155)
[text/plain] v3-0003-add-helper-functions-for-fast-path-arg-setup.patch (6.0K, ../aiCeYhW4Ksu-BFqC@nathan/4-v3-0003-add-helper-functions-for-fast-path-arg-setup.patch)
download | inline diff:
From e5b1df7a69d0d0f1798ce0dc2beb18fedfdfd081 Mon Sep 17 00:00:00 2001
From: Reviewer <review@example.com>
Date: Tue, 2 Jun 2026 18:24:30 +0000
Subject: [PATCH v3 3/3] add helper functions for fast-path arg setup
---
src/interfaces/libpq/fe-lobj.c | 104 ++++++++++++---------------------
1 file changed, 38 insertions(+), 66 deletions(-)
diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.cindex 42b2a36bda9..8802c6f8098 100644--- a/src/interfaces/libpq/fe-lobj.c+++ b/src/interfaces/libpq/fe-lobj.c@@ -44,6 +44,22 @@
static int lo_initialize(PGconn *conn);
static Oid lo_import_internal(PGconn *conn, const char *filename, Oid oid);
+static inline void+lo_set_int_arg(PQArgBlock *arg, int value)+{+ arg->isint = 1;+ arg->len = 4;+ arg->u.integer = value;+}++static inline void+lo_set_ptr_arg(PQArgBlock *arg, const void *ptr, int len)+{+ arg->isint = 0;+ arg->len = len;+ arg->u.ptr = (int *) unconstify(void *, ptr);+}+
/*
* lo_open
* opens an existing large object
@@ -62,13 +78,9 @@ lo_open(PGconn *conn, Oid lobjId, int mode)
if (lo_initialize(conn) < 0)
return -1;
- argv[0].isint = 1;- argv[0].len = 4;- argv[0].u.integer = lobjId;+ lo_set_int_arg(&argv[0], lobjId);- argv[1].isint = 1;- argv[1].len = 4;- argv[1].u.integer = mode;+ lo_set_int_arg(&argv[1], mode);
res = PQnfn(conn, conn->lobjfuncs->fn_lo_open, &fd, -1, &result_len, 1, argv, 2);
if (PQresultStatus(res) == PGRES_COMMAND_OK)
@@ -101,9 +113,7 @@ lo_close(PGconn *conn, int fd)
if (lo_initialize(conn) < 0)
return -1;
- argv[0].isint = 1;- argv[0].len = 4;- argv[0].u.integer = fd;+ lo_set_int_arg(&argv[0], fd);
res = PQnfn(conn, conn->lobjfuncs->fn_lo_close,
&retval, -1, &result_len, 1, argv, 1);
if (PQresultStatus(res) == PGRES_COMMAND_OK)
@@ -159,13 +169,9 @@ lo_truncate(PGconn *conn, int fd, size_t len)
return -1;
}
- argv[0].isint = 1;- argv[0].len = 4;- argv[0].u.integer = fd;+ lo_set_int_arg(&argv[0], fd);- argv[1].isint = 1;- argv[1].len = 4;- argv[1].u.integer = (int) len;+ lo_set_int_arg(&argv[1], (int) len);
res = PQnfn(conn, conn->lobjfuncs->fn_lo_truncate,
&retval, -1, &result_len, 1, argv, 2);
@@ -207,14 +213,10 @@ lo_truncate64(PGconn *conn, int fd, int64_t len)
return -1;
}
- argv[0].isint = 1;- argv[0].len = 4;- argv[0].u.integer = fd;+ lo_set_int_arg(&argv[0], fd);
len = pg_hton64(len);
- argv[1].isint = 0;- argv[1].len = 8;- argv[1].u.ptr = (int *) &len;+ lo_set_ptr_arg(&argv[1], &len, 8);
res = PQnfn(conn, conn->lobjfuncs->fn_lo_truncate64,
&retval, -1, &result_len, 1, argv, 2);
@@ -261,13 +263,9 @@ lo_read(PGconn *conn, int fd, char *buf, size_t len)
return -1;
}
- argv[0].isint = 1;- argv[0].len = 4;- argv[0].u.integer = fd;+ lo_set_int_arg(&argv[0], fd);- argv[1].isint = 1;- argv[1].len = 4;- argv[1].u.integer = (int) len;+ lo_set_int_arg(&argv[1], (int) len);
res = PQnfn(conn, conn->lobjfuncs->fn_lo_read,
(void *) buf, len, &result_len, 0, argv, 2);
@@ -312,13 +310,9 @@ lo_write(PGconn *conn, int fd, const char *buf, size_t len)
return -1;
}
- argv[0].isint = 1;- argv[0].len = 4;- argv[0].u.integer = fd;+ lo_set_int_arg(&argv[0], fd);- argv[1].isint = 0;- argv[1].len = (int) len;- argv[1].u.ptr = (int *) unconstify(char *, buf);+ lo_set_ptr_arg(&argv[1], buf, (int) len);
res = PQnfn(conn, conn->lobjfuncs->fn_lo_write,
&retval, -1, &result_len, 1, argv, 2);
@@ -349,17 +343,11 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
if (lo_initialize(conn) < 0)
return -1;
- argv[0].isint = 1;- argv[0].len = 4;- argv[0].u.integer = fd;+ lo_set_int_arg(&argv[0], fd);- argv[1].isint = 1;- argv[1].len = 4;- argv[1].u.integer = offset;+ lo_set_int_arg(&argv[1], offset);- argv[2].isint = 1;- argv[2].len = 4;- argv[2].u.integer = whence;+ lo_set_int_arg(&argv[2], whence);
res = PQnfn(conn, conn->lobjfuncs->fn_lo_lseek,
&retval, -1, &result_len, 1, argv, 3);
@@ -397,18 +385,12 @@ lo_lseek64(PGconn *conn, int fd, int64_t offset, int whence)
return -1;
}
- argv[0].isint = 1;- argv[0].len = 4;- argv[0].u.integer = fd;+ lo_set_int_arg(&argv[0], fd);
offset = pg_hton64(offset);
- argv[1].isint = 0;- argv[1].len = 8;- argv[1].u.ptr = (int *) &offset;+ lo_set_ptr_arg(&argv[1], &offset, 8);- argv[2].isint = 1;- argv[2].len = 4;- argv[2].u.integer = whence;+ lo_set_int_arg(&argv[2], whence);
res = PQnfn(conn, conn->lobjfuncs->fn_lo_lseek64,
(void *) &retval, sizeof(retval), &result_len, 0, argv, 3);
@@ -443,9 +425,7 @@ lo_creat(PGconn *conn, int mode)
if (lo_initialize(conn) < 0)
return InvalidOid;
- argv[0].isint = 1;- argv[0].len = 4;- argv[0].u.integer = mode;+ lo_set_int_arg(&argv[0], mode);
res = PQnfn(conn, conn->lobjfuncs->fn_lo_creat,
&retval, -1, &result_len, 1, argv, 1);
if (PQresultStatus(res) == PGRES_COMMAND_OK)
@@ -487,9 +467,7 @@ lo_create(PGconn *conn, Oid lobjId)
return InvalidOid;
}
- argv[0].isint = 1;- argv[0].len = 4;- argv[0].u.integer = lobjId;+ lo_set_int_arg(&argv[0], lobjId);
res = PQnfn(conn, conn->lobjfuncs->fn_lo_create,
&retval, -1, &result_len, 1, argv, 1);
if (PQresultStatus(res) == PGRES_COMMAND_OK)
@@ -520,9 +498,7 @@ lo_tell(PGconn *conn, int fd)
if (lo_initialize(conn) < 0)
return -1;
- argv[0].isint = 1;- argv[0].len = 4;- argv[0].u.integer = fd;+ lo_set_int_arg(&argv[0], fd);
res = PQnfn(conn, conn->lobjfuncs->fn_lo_tell,
&retval, -1, &result_len, 1, argv, 1);
@@ -560,9 +536,7 @@ lo_tell64(PGconn *conn, int fd)
return -1;
}
- argv[0].isint = 1;- argv[0].len = 4;- argv[0].u.integer = fd;+ lo_set_int_arg(&argv[0], fd);
res = PQnfn(conn, conn->lobjfuncs->fn_lo_tell64,
(void *) &retval, sizeof(retval), &result_len, 0, argv, 1);
@@ -594,9 +568,7 @@ lo_unlink(PGconn *conn, Oid lobjId)
if (lo_initialize(conn) < 0)
return -1;
- argv[0].isint = 1;- argv[0].len = 4;- argv[0].u.integer = lobjId;+ lo_set_int_arg(&argv[0], lobjId);
res = PQnfn(conn, conn->lobjfuncs->fn_lo_unlink,
&retval, -1, &result_len, 1, argv, 1);
--
2.50.1 (Apple Git-155)
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Reply to all the recipients using the --to and --cc options:
reply via email
To: pgsql-hackers@postgresql.org
Cc: nathandbossart@gmail.com, jacob.champion@enterprisedb.com
Subject: Re: future of PQfn()
In-Reply-To: <aiCeYhW4Ksu-BFqC@nathan>
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
This inbox is served by DDX for PostgreSQL; see mirroring instructions
for how to clone and mirror all data and code used for this inbox