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 1wV9W8-001jOM-2O for pgsql-hackers@arkaria.postgresql.org; Thu, 04 Jun 2026 14:57:57 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.96) (envelope-from ) id 1wV9W7-0073c9-0C for pgsql-hackers@arkaria.postgresql.org; Thu, 04 Jun 2026 14:57:55 +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 1wV9W6-0073c1-2G for pgsql-hackers@lists.postgresql.org; Thu, 04 Jun 2026 14:57:54 +0000 Received: from mail-ot1-x331.google.com ([2607:f8b0:4864:20::331]) by magus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (Exim 4.98.2) (envelope-from ) id 1wV9W4-00000001FxA-3GU6 for pgsql-hackers@postgresql.org; Thu, 04 Jun 2026 14:57:54 +0000 Received: by mail-ot1-x331.google.com with SMTP id 46e09a7af769-7e6b5c374e5so871746a34.0 for ; Thu, 04 Jun 2026 07:57:52 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1780585070; x=1781189870; darn=postgresql.org; h=in-reply-to:content-transfer-encoding:content-disposition :mime-version:references:message-id:subject:cc:to:from:date:from:to :cc:subject:date:message-id:reply-to; bh=Ihm7VzzDqGd8nIBjqYjAuiIC9rg6uTvGXppfiiW6ZQs=; b=XQ+Hv30W+EbP0VoYJ0pOrqPD6S3H3sOfpFV1DQeU7E2jHaU/lFUHJTFhlGqSJlocJq fW0VkDdk/7NpN211tOGaiSNh91vkbPAJ8N3vJ/KD6VtZRNcHdXLpuM3aOlZhPbGGKcNN 5z/bddk0dsi9iiqMjV93WM+LLc0bP7ZYiRrx68IjG4ixfr73OIkbHTz4DZIQ6MD3GfOJ QHgRsGHAZX/DdaF3QsR/v1L2TkaXbeiLuSZ7hbKmwHADRMlYsPPqVdFg31OA8SyRXL77 7EXtdymSb5YmDI6MgEyab9iWyoxhh5VtuRcWQ2whLWK2dk81wq5lEC8z/6l2ksXZF4vu LerA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1780585070; x=1781189870; h=in-reply-to:content-transfer-encoding:content-disposition :mime-version:references:message-id:subject:cc:to:from:date:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=Ihm7VzzDqGd8nIBjqYjAuiIC9rg6uTvGXppfiiW6ZQs=; b=htpw2B0UGOmb3kxupFdkJhaXBLKcm4roEbxXnhCAAZ+jA4Z2KlLVwcw5jZxL4ZhsrQ v/WuiBuxw63e7SRCP53V5lwRDF8BjeG/cD2V6kM36tzI1LG5gHkJooph5sKZrPg+TXJp /Gpn/5kf3o3RC5YKeQ+mFma8gHZXXrNFeIRl9x3jB92JIJRbyPP6Z42NYDUv3lfbFjgW h7nxpLLGbngWEkesrAsCbWocP40XitfPwYnMfBGHnxLWIJA8irvRZ7H/WEiUQWwiaGTG iBH6MXiFzCyQvrg+o65Xy+5csN3R5N56Bu2kF76ZK/L1+zBC5IHyqK6XM0zCFvj475eR 7e9A== X-Forwarded-Encrypted: i=1; AFNElJ9FWi8V85uZG4wA/EOp57FXeUZg6MH1y/c9KQhzQusEmRQHVe6feAEfWk5hKmpAZwg7Rw/zW9o8hJOY8iaR@postgresql.org X-Gm-Message-State: AOJu0YxyX6BUlQPOd+odxW3kKM44NxVbm2GW4HB6RjLSDbAL42z/3eYI 5cGiq3nbC+qnu17SJR1TSeRZmnXs2jBLnbmE8OhD0LzOcHJstvg8HQFG X-Gm-Gg: Acq92OHBjuorVPkj+CnuQYG0PIezFLu3cGVYAnVQmk+bgsRdvpk52UF/EmgxhfkqvsC 1VQkpyHa57aqVUz05SfqxBBg22I/wYBnqp94kJjLVAOUtHlw5Vdj+TqbEB3+rd+YsOD/wv2yznO pPXviNwfKLyM0j5gBKcJ/cLbJfmNf4j1fYx6JsffoeXpROlC9QzPepL7JOA4jXb77sl0WKvWG0K z9IIfFgeAyOJhLFXOe82pIya8jgV5aQEjj6Es7rXs7f8+VNxoeJFJ705Skci981qsTCM9fnCTNL Jg1CM3gx42juwwDcEO2aGVYqCzrtFTBDBZqzVwZLJXbM6dqMPYKDIxOGrsk2Og7OSecOQ1xgCq+ 6ejzJ/CVZNd520I7oqeTwiLQZBYXqWgqfJlDFjvX7HfbPLV0sJBWBWov+cedAk4TbnVhN9pQAy3 nrDcryOPWTBz1iwxQ/HVTuQEtvaSiOqqOsCBkX+M5MXUgyvgAs1AeJCgOduTV0EqH4ajh0HYSan lBW/tvcoEwI+mJYR3APmC+zZXuKAn4A X-Received: by 2002:a9d:6a93:0:b0:7db:a297:9e62 with SMTP id 46e09a7af769-7e6f93f2097mr1546679a34.8.1780585070525; Thu, 04 Jun 2026 07:57:50 -0700 (PDT) Received: from nathan (162-195-168-172.lightspeed.stlsmo.sbcglobal.net. [162.195.168.172]) by smtp.gmail.com with ESMTPSA id 46e09a7af769-7e6e78de92fsm3959167a34.18.2026.06.04.07.57.49 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 04 Jun 2026 07:57:49 -0700 (PDT) Date: Thu, 4 Jun 2026 09:57:47 -0500 From: Nathan Bossart To: Dagfinn Ilmari =?utf-8?Q?Manns=C3=A5ker?= Cc: Jacob Champion , pgsql-hackers@postgresql.org Subject: Re: future of PQfn() Message-ID: References: <87ldcu1tfd.fsf@wibble.ilmari.org> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="Z10p9YYojB0/BzD2" Content-Disposition: inline Content-Transfer-Encoding: 8bit In-Reply-To: <87ldcu1tfd.fsf@wibble.ilmari.org> List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk --Z10p9YYojB0/BzD2 Content-Type: text/plain; charset=utf-8 Content-Disposition: inline Content-Transfer-Encoding: 8bit On Thu, Jun 04, 2026 at 11:39:02AM +0100, Dagfinn Ilmari Mannsåker wrote: > Nathan Bossart writes: > >> - >> - The Fast-Path Interface >> - >> - >> - fast path >> - > > Should we move this to the "Obsolete or Renamed Features" appendix > (e.g. appendix-obsolete-libpq-fastpath.sgml) with a description of why > it was removed? Yes, I think we should. Done in the attached. -- nathan --Z10p9YYojB0/BzD2 Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename=v4-0001-remove-PQfn.patch From 63486371b3531be66bb8e0c62ef1b8cc7e95abb5 Mon Sep 17 00:00:00 2001 From: Nathan Bossart Date: Mon, 1 Jun 2026 16:55:00 -0500 Subject: [PATCH v4 1/3] remove PQfn --- .../appendix-obsolete-libpq-fastpath.sgml | 24 ++++ doc/src/sgml/appendix-obsolete.sgml | 1 + doc/src/sgml/filelist.sgml | 1 + 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 +++--- 8 files changed, 86 insertions(+), 145 deletions(-) create mode 100644 doc/src/sgml/appendix-obsolete-libpq-fastpath.sgml diff --git a/doc/src/sgml/appendix-obsolete-libpq-fastpath.sgml b/doc/src/sgml/appendix-obsolete-libpq-fastpath.sgml new file mode 100644 index 00000000000..e42c2ece487 --- /dev/null +++ b/doc/src/sgml/appendix-obsolete-libpq-fastpath.sgml @@ -0,0 +1,24 @@ + + + + + <application>libpq</application> Fast-Path Interface Removed + + + fast path + + + + In PostgreSQL 19 and below, + libpq supported a fast-path interface to send + simple function calls to the server. This interface was unsafe and + obsolete, and thus was removed in PostgreSQL 20. + 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. + + + diff --git a/doc/src/sgml/appendix-obsolete.sgml b/doc/src/sgml/appendix-obsolete.sgml index cc002653052..11a033112ef 100644 --- a/doc/src/sgml/appendix-obsolete.sgml +++ b/doc/src/sgml/appendix-obsolete.sgml @@ -39,5 +39,6 @@ &obsolete-pgresetxlog; &obsolete-pgreceivexlog; &obsolete-auth-radius; + &obsolete-libpq-fastpath; diff --git a/doc/src/sgml/filelist.sgml b/doc/src/sgml/filelist.sgml index 25a85082759..7dbe741d729 100644 --- a/doc/src/sgml/filelist.sgml +++ b/doc/src/sgml/filelist.sgml @@ -209,3 +209,4 @@ + diff --git a/doc/src/sgml/libpq.sgml b/doc/src/sgml/libpq.sgml index 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 COPY. Using synchronous command execution functions - such as PQfn, + such as PQexec, PQexecParams, PQprepare, @@ -7046,121 +7046,6 @@ int PQrequestCancel(PGconn *conn); - - The Fast-Path Interface - - - fast path - - - - PostgreSQL provides a fast-path interface - to send simple function calls to the server. - - - - - This interface is unsafe and should not be used. When - result_is_int is set to 0, - PQfn may write data beyond the end of - result_buf, 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. - - - - - The function PQfnPQfn - requests execution of a server function via the fast-path interface: - -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; - - - - - The fnid argument is the OID of the function to be - executed. args and nargs define the - parameters to be passed to the function; they must match the declared - function argument list. When the isint field of a - parameter structure is true, the u.integer 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 isint - is false, the indicated number of bytes at *u.ptr 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 u.ptr as being of - type int * is historical; it would be better to consider - it void *.) - result_buf 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 - result_len. If a 2- or 4-byte integer result - is expected, set result_is_int to 1, otherwise - set it to 0. Setting result_is_int to 1 causes - libpq to byte-swap the value if necessary, so that it - is delivered as a proper int value for the client machine; - note that a 4-byte integer is delivered into *result_buf - for either allowed result size. - When result_is_int is 0, the binary-format byte string - sent by the server is returned unmodified. (In this case it's better - to consider result_buf as being of - type void *.) - - - - PQfn always returns a valid - PGresult pointer, with - status PGRES_COMMAND_OK for success - or PGRES_FATAL_ERROR if some problem was encountered. - The result status should be - checked before the result is used. The caller is responsible for - freeing the PGresult with - when it is no longer needed. - - - - To pass a NULL argument to the function, set - the len field of that parameter structure - to -1; the isint - and u fields are then irrelevant. - - - - If the function returns NULL, *result_len is set - to -1, and *result_buf is not - modified. - - - - 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. - - - - Asynchronous Notification diff --git a/src/backend/tcop/fastpath.c b/src/backend/tcop/fastpath.c index 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.h index 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.c index 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.c index 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) --Z10p9YYojB0/BzD2 Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename=v4-0002-remove-lo_hton64-and-lo_ntoh64.patch From 181028cbf820700f104f48dfc0e94d0c7f5e42e0 Mon Sep 17 00:00:00 2001 From: Reviewer Date: Tue, 2 Jun 2026 17:22:48 +0000 Subject: [PATCH v4 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.c index 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) --Z10p9YYojB0/BzD2 Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename=v4-0003-add-helper-functions-for-fast-path-arg-setup.patch From 8e5a937d5e302a56ff2118ce3ea4f69e7db5ae9f Mon Sep 17 00:00:00 2001 From: Reviewer Date: Tue, 2 Jun 2026 18:24:30 +0000 Subject: [PATCH v4 3/3] add helper functions for fast-path arg setup --- src/interfaces/libpq/fe-lobj.c | 110 ++++++++++++--------------------- 1 file changed, 38 insertions(+), 72 deletions(-) diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c index 42b2a36bda9..e8f6d958e84 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,8 @@ 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; - - argv[1].isint = 1; - argv[1].len = 4; - argv[1].u.integer = mode; + lo_set_int_arg(&argv[0], lobjId); + 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 +112,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 +168,8 @@ lo_truncate(PGconn *conn, int fd, size_t len) return -1; } - argv[0].isint = 1; - argv[0].len = 4; - argv[0].u.integer = fd; - - argv[1].isint = 1; - argv[1].len = 4; - argv[1].u.integer = (int) len; + lo_set_int_arg(&argv[0], fd); + 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 +211,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 +261,8 @@ 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; - - argv[1].isint = 1; - argv[1].len = 4; - argv[1].u.integer = (int) len; + lo_set_int_arg(&argv[0], fd); + 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 +307,8 @@ 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; - - argv[1].isint = 0; - argv[1].len = (int) len; - argv[1].u.ptr = (int *) unconstify(char *, buf); + lo_set_int_arg(&argv[0], fd); + 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 +339,9 @@ 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; - - argv[1].isint = 1; - argv[1].len = 4; - argv[1].u.integer = offset; - - argv[2].isint = 1; - argv[2].len = 4; - argv[2].u.integer = whence; + lo_set_int_arg(&argv[0], fd); + lo_set_int_arg(&argv[1], offset); + lo_set_int_arg(&argv[2], whence); res = PQnfn(conn, conn->lobjfuncs->fn_lo_lseek, &retval, -1, &result_len, 1, argv, 3); @@ -397,18 +379,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 +419,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 +461,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 +492,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 +530,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 +562,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) --Z10p9YYojB0/BzD2--